第四次模拟赛订正题解
Posted tyouchie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四次模拟赛订正题解相关的知识,希望对你有一定的参考价值。
这次考动态规划专练;
下一次考数据结构专练???
坦白讲:这东西我还是不会;
现在发现好像是一个叫做树的最大独立集的;
有个暴力40分的做法,预处理所有的深度(层数),不是相邻层的累加,最后比较max,这个复杂度过不去,也只是贪心的思想,所以写完爆搜之后我还是去写了树形dp;
我们用dp[i][K]表示当前节点i选择(k==1)或不选择(k==0);而且比较巧妙地是,在统计方案树的是否,我们直接可以用当前k的表示该节点的方案,累加即可,好妙啊;
给出的题解:
#include<bits/stdc++.h> using namespace std; #define N 1000010 vector<int> G[N]; int n,u,v; template<typename T>inline void read(T &x) x=0;T f=1,ch=getchar(); while(!isdigit(ch)) if(ch==‘-‘) f=-1; ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); x*=f; void dfs(int u,int fa) for(int i=0;i<G[u].size();i++) if(G[u][i]!=fa) dfs(G[u][i],u); int d[N][2]=0; int dp(int u,int k,int fa) d[u][k]=k; for(int i=0;i<G[u].size();i++) if(G[u][i]!=fa) if(k)//如果选,子节点不选 d[u][k]+=dp(G[u][i],0,u); else//如果不选,选子节点或不选子节点 d[u][k]+=max(dp(G[u][i],0,u),dp(G[u][i],1,u)); return d[u][k]; int main() freopen("a.in","r",stdin); freopen("a.out","w",stdout); read(n); for(int i=1;i<n;i++) read(u); read(v); G[u].push_back(v); G[v].push_back(u); dfs(1,-1); cout<<max(dp(1,0,-1),dp(1,1,-1)); return 0;
第二题:
环形合并石子:区间dp;破环为链,复制一倍;
#include<bits/stdc++.h> using namespace std; #define N 1000 template<typename T>inline void read(T &x) x=0;T f=1,ch=getchar(); while(!isdigit(ch)) if(ch==‘-‘) f=-1; ch=getchar(); while(isdigit(ch)) x=x*10+ch-‘0‘; ch=getchar(); x*=f; int n,a[N],sum[N],h[N][N]; int main() freopen("b.in","r",stdin); freopen("b.out","w",stdout); read(n); memset(h,0xcf,sizeof(h)); for(int i=1;i<=n;i++) read(a[i]),a[i+n]=a[i]; for(int i=1;i<=n*2;i++) sum[i]=sum[i-1]+a[i],h[i][i]=0; for(int len=2;len<=n;len++) for(int l=1;l+len<=n*2+1;l++) int r=l+len-1; for(int k=1;k<r;k++) h[l][r]=max(h[l][r],h[l][k]+h[k+1][r]+sum[r]-sum[l-1]); int ans2=-(1<<30); for(int i=1;i<=n;i++) ans2=max(ans2,h[i][i+n-1]); cout<<ans2<<endl; return 0;
第三题:
看数据范围:
非常容易想到状压dp,本身就是一种暴力做法;
dp[i][j]表示当前i状态下,最后一位放的是j,感觉好套路啊这样的状态;
那么我们只需要判断当前状态下是否能放w,状态转移是累加方案即可;
给出的题解:
竟然考了状压dp;
#include<bits/stdc++.h> using namespace std; #define N 20 template<typename T>inline void read(T &x) x=0;T f=1,ch=getchar(); while(!isdigit(ch)) if(ch==‘-‘) f=-1; ch=getchar(); while(isdigit(ch)) x=x*10+ch-‘0‘; ch=getchar(); x*=f; long long n,k,a[N],f[1<<N][N]; long long ans; int main() freopen("c.in","r",stdin); freopen("c.out","w",stdout); read(n); read(k); for(int i=1;i<=n;++i) read(a[i]); f[1<<(i-1)][i]=1;//第i位放i的方案初始化1 for(int i=1;i<(1<<n);++i) //枚举状态 for(int j=1;j<=n;++j) //当前放j for(int w=1;w<=n;++w) //下一个放w if(i&(1<<(w-1))) continue;//如果当前状态下w位不能放w if(abs(a[j]-a[w])>k) //满足题目要求的k可以放 f[i|(1<<(w-1))][w]+=f[i][j];//更新状态,累加答案 for(int i=1;i<=n;++i) ans+=f[(1<<n)-1][i]; cout<<ans<<endl; return 0;
最后祝贺Chdy大佬不到一个小时AK;
以上是关于第四次模拟赛订正题解的主要内容,如果未能解决你的问题,请参考以下文章