【牛客IOI周赛16-普及组】补题,树形DP
A
签到题,本质上是求
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD=1e9+7;
int main()
{
int n;ll ans=1;cin>>n;
while(n){
ans=(ans%MOD*n%MOD)%MOD;
n--;
}
cout<<ans;
} B 猜数---排序和不排序两种做法
原数组排序,从前以后依次加上,一直加到大于等于给定m 。相当于一种贪心,从最多的差值开始加,一直加到大于m此时遍历的数就为最少改动数。 时间
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int num[1000005];
int main(){
int n,m;
cin>>n>>m;
ll sum=0;
for(int i=0;i<n;++i){
cin>>num[i];
sum+=num[i];
}
sort(num,num+n);
int tmp=sum;int ans=1;
for(int i=0;i<n;++i){
tmp+=9-num[i];
if(tmp>=m){
break;
}else ans++;
}
cout<<ans;
}IOI赛制要求执行效率,考虑不排序做法:
上面做法排序是为了遵循先加上比较大的差值,那么可以先统计原数组0-9的个数,然后枚举差值即可,常数时间复杂度。
#include <bits/stdc++.h>
using namespace std;
int cnt[10];
int n,m,ans,sum;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;cin>>x;
cnt[x]++,sum+=x;
}
for(int i=0;i<10;i++){
int d=9-i;//枚举差值,差值无非就是0~9
int now=cnt[i]*d;
if(sum+now<m) sum+=now,ans+=cnt[i];
else{
ans+=(m-sum)%d==0?(m-sum)/d:(m-sum)/d+1;
break;
}
}
printf("%d\n",ans);
return 0;
} C
找规律,推出递推公式:
看了官方题解觉得这个题出的真不错——f[i]表示i*i的矩阵的方法数
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD = 1e9+7;
int nn,n;
ll f[100005];
int main()
{
cin>>n;
f[0]=1;f[1]=1;
for(int i=2;i<=n;++i){
f[i]=(f[i-1]%MOD+(i-1)%MOD*f[i-2]%MOD)%MOD;
}
cout<<f[n]%MOD;
} D
参考大佬题解https://blog.nowcoder.net/n/9672836159594b519ceebcdb658ab6c2 表示 u 这个节点,最长链小于等于j的最小代价。
转移过程中要用tmp[i]来保存dp[u][i]过程值
转移方程:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e3+7;
const int INF = 0x3f3f3f3f;
int a[N],f[N][N],tmp[N];
vector<int> e[N];
int n,l;
void dfs(int u,int fa){
f[u][0]=a[u]; //删除自己
for(auto child : e[u])if(child!=fa){
dfs(child,u);
f[u][0]+=*min_element(f[child],f[child]+l); //删除自己 同时子树最长链也小于等于l
for(int i=1; i<l; ++i)
tmp[i]=f[u][i],f[u][i]=INF;
for(int i=1; i<l;++i){ //不删除自己
for(int j=0; j<l; ++j){ //子树最长链满足小于等于j
if(i+j<l) f[u][max(i,j+1)]=min(f[u][max(i,j+1)],tmp[i]+f[child][j]);
else break;
}
}
}
}
int main(){
cin>>n>>l;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<n;++i){
int u,v;cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0);
printf("%d\n",*min_element(f[1],f[1]+l));
return 0;
}
查看17道真题和解析