#include<bits/stdc++.h>#define int long longusingnamespacestd;constintINF=0x3f3f3f3f;constintM=1e9+7;constintmaxn=1e5+5;intn,d;vector<int>G[maxn];intf[maxn][2],g[maxn][2];voiddfs(intu=1,intpar=0){g[u][0]=g[u][1]=1;f[u][0]=0,f[u][1]=0;for(autov:G[u]){if(par==v)continue;dfs(v,u);f[u][0]=(g[u][0]*(g[v][0]+f[v][0]))%M+(f[u][0]*(f[v][0]+g[v][0]+f[v][1]))%M;f[u][0]%=M;f[u][1]=(g[u][1]*(g[v][1]+f[v][1]))%M+(f[u][1]*(f[v][1]+g[v][1]+f[v][0]))%M;f[u][1]%=M;g[u][0]*=f[v][1];g[u][0]%=M;g[u][1]*=f[v][0];g[u][1]%=M;}}signedmain(){cin>>n;for(inti=0;i<n-1;i++){intu,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}dfs();cout<<(f[1][0]+f[1][1])%M<<"\n";}
#include<bits/stdc++.h>#define int long long#define F first#define S secondusingnamespacestd;constintmaxn=5050;vector<int>G[maxn];intsz[maxn];intans=0;voiddfs1(intu,intpar){sz[u]=1;for(autov:G[u]){if(v==par)continue;dfs1(v,u);sz[u]+=sz[v];}}voiddfs2(intu,intpar){vector<pair<int,int>>sizes;for(autov:G[u]){if(v==par)continue;sizes.push_back({sz[v],v});}for(autox:sizes){dfs2(x.S,u);}vector<int>dp(sz[u]+1,false);dp[0]=true;for(inti=0;i<(int)sizes.size();i++){vector<int>newDp(sz[u]+1,false);for(intj=0;j<=sz[u];j++){// takeif(j>=sizes[i].F)newDp[j]|=dp[j-sizes[i].F];// not takenewDp[j]|=dp[j];}swap(dp,newDp);}intmxAdd=0;for(intj=0;j<=sz[u];j++){if(dp[j])mxAdd=max(mxAdd,j*(sz[u]-1-j));}ans+=mxAdd;}voidsolve(){intn;cin>>n;for(inti=1;i<n;i++){intv;cin>>v;v--;G[i].push_back(v);G[v].push_back(i);}dfs1(0,-1);dfs2(0,-1);cout<<ans<<'\n';}signedmain(){solve();}
#include<bits/stdc++.h>usingnamespacestd;#define int long longconstintmaxn=1e5+5;intn;intw[maxn],dp[maxn][2];;vector<int>G[maxn];voidupdate(int&x,inty){if(x<y)x=y;}voiddfs(intu,intpa){intsum=0;for(autov:G[u]){if(v==pa)continue;dfs(v,u);sum+=max(dp[v][0],dp[v][1]);}dp[u][0]=dp[u][1]=sum;for(autov:G[u]){if(v==pa)continue;update(dp[u][0],sum+dp[v][0]+w[v]-w[u]-max(dp[v][0],dp[v][1]));update(dp[u][1],sum+dp[v][1]+w[u]-w[v]-max(dp[v][0],dp[v][1]));}}signedmain(){cin>>n;for(inti=1;i<=n;i++){cin>>w[i];}for(inti=1;i<n;i++){intu,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}dfs(1,1);cout<<max(dp[1][0],dp[1][1])<<'\n';}
問方法數,我們自然而然會想到樹 dp。假設一個 v 為根子樹內的合法方案數是 dp(v),我們考慮如何轉移上去 v 的 parent u。我們發現我們無法區分子樹內選得點有祖孫關係還是沒有祖孫關係,因為這會關係到我們 u 如果一定要選的合法方案數,這會造成 dp(v) 內有祖孫關係直接是不合法的,而沒有祖孫關係的合法。
所以我們需要區分這兩種狀態,令:
dp(i, 0): 以 i 為根的子樹有選的點「不存在祖孫關係」的合法方法數
dp(i, 1): 以 i 為根的子樹有選的點「恰有祖孫關係」的合法方法數
考慮 v 與他的父親 u 的轉移,dp(u, 0) 由於不能有祖孫關係,所以當 u 點要選時,下面的點都不能選,為 1 種方法數,如果不選 u,則就是下面的每顆子樹的 dp(v, 0) 相乘起來。dp(u, 1) 由於一定要有祖孫關係,但又要合法,所以當 u 選的時候,下面只能挑一顆沒有祖孫關係的子樹,也就是將每顆子樹 dp(v, 0) 扣 1 樹加起來,扣 1 的原因是要扣除什麼都沒挑的情況,當 u 不選的時候,就是枚舉哪顆子樹要有祖孫關係,其他的子樹什麼都不能選,也就是 dp(v, 1) 加起來。我們統整一下,轉移式為:
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintMAXN=2e6+5;constintmod=998244353;vector<int>G[MAXN];intdp[MAXN][2];voiddfs(intu,intlst){dp[u][0]=1;// leaf 有 1 種選法叫做什麼都不選dp[u][1]=0;for(autov:G[u]){if(v==lst)continue;dfs(v,u);dp[u][0]=(dp[v][0])*dp[u][0]%mod;dp[u][1]=(dp[v][0]-1+dp[v][1]+dp[u][1])%mod;}dp[u][0]++;// 只選 u}voidsolve(){intn;cin>>n;for(inti=1;i<=n;i++){G[i].clear();}for(inti=0;i<n-1;i++){intu,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}dfs(1,0);cout<<(dp[1][0]+dp[1][1])%mod<<endl;}signedmain(){intt=1;cin>>t;while(t--){solve();}}