【牛客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; }