P8352 [SDOI/SXOI2022] 小 N 的独立集
碎碎念
不会写难题,随简单省选题切一切捏。
注意到,一定是要钦定所有的 nk 种权值之后再去算方案的。
对于最大权独立集,我们可以设。
dp[x][0/1][v] 表示 x 选/不选,其子树内已经选了权值 v 作为其最大独立集的方案数。
就是这个捏。
需要注意的是,如何处理所钦定的 v 统计的方案一定为其为子树的最大独立集呢。
首先我们在钦定完 x 的状态后,x 子树的最大独立集一定由其儿子的最大独立集并起来。
我不会。
不妨先考虑 k=2。
maybe dp of dp.
乐子。会了。
乐子,我又不会了。
dpofdp.
dp[x][(f_x_0,f_x_1)]
dp[y][f_y_0,f_y_1] to dp[x][(f_x_0+max(f_y_0,f_y_1),f_x_1+f_y_0)]
init:
dp[x][(0,i)]=1,i\in [1,K]
考虑分析 f_x_0,f_x_1 的性质。一般为差/前缀max/min。
dp[x][f_x_0][d] 表示 f_x_1=f_x_0+d,d\in[-5,5]
d=f_x_1-f_x0
大力转移即可。
how
你把平凡的 dp 树上最大独立集的式子写出来,发现没啥性质!但是考虑 dp of dp 的典中典套路,做个前缀 max!即 \(f(x,0)\) 为不选的最大独立集,\(f(x,1)\) 为可以选也可以不选的最大独立集。然后再典中典,考虑差分!首先 \(f(x,1)-f(x,0)\ge 0\),接下来,\(f(x,0)=\sum f(y,1),f(x,1)=a_x+\sum f(y,0)\),\(d=f(y,1)-f(y,0)=a_x-\sum f(y,0)-f(y,1)\le a_x\),发现取 \(a_x\) 取 \(k\) 达上界。
随便做下去即可。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int mod=(int)(1e9+7),N=1002,B=22;
vector<int>g[N];
int n,K,sz[N];
int dp[N][N*5+1][8],pre[N*5+1][8];
int ans[N*5+5];
void dfs(int x,int ff) {
for(int i=1;i<=K;i++) dp[x][0][i]=1;
sz[x]=1;
for(int y:g[x]) {
if(y==ff) continue ;
dfs(y,x);
for(int i=0;i<=sz[x]*K;i++) {
for(int jj=0;jj<=K;jj++) {
int fx0=i,fx1=i+jj;
pre[fx0][fx1-fx0]=dp[x][fx0][fx1-fx0];
dp[x][fx0][fx1-fx0]=0;
}
}
for(int i=0;i<=sz[y]*K;i++) {
for(int j=0;j<=K;j++) {
int fy0=i,fy1=i+j;
if(!dp[y][fy0][fy1-fy0]) continue ;
for(int k=0;k<=sz[x]*K;k++) {
for(int jj=0;jj<=K;jj++) {
int fx0=k,fx1=k+jj;
if(!pre[fx0][fx1-fx0]) continue ;
int n0=fx0+max(fy0,fy1),n1=max(n0,fx1+fy0);
// cout<<n1-n0<<'\n';
// if(n1-n0<0) n1=n0;
dp[x][n0][n1-n0]=(dp[x][n0][n1-n0]+pre[fx0][fx1-fx0]*dp[y][fy0][fy1-fy0]%mod)%mod;
}
}
}
}
sz[x]+=sz[y];
}
}
signed main() {
// freopen("2.in","r",stdin); freopen("xgf.out","w",stdout);
cin.tie(0); ios::sync_with_stdio(false);
cin>>n>>K;
for(int i=1;i<n;i++) {
int x,y; cin>>x>>y;
g[x].pb(y); g[y].pb(x);
}
dfs(1,0);
for(int i=0;i<=n*K;i++) {
for(int j=0;j<=K;j++) {
int fx0=i,fx1=i+j;
ans[max(fx0,fx1)]=(ans[max(fx0,fx1)]+dp[1][fx0][fx1-fx0])%mod;
}
}
for(int i=1;i<=n*K;i++) cout<<(ans[i]%mod+mod)%mod<<'\n';
return 0;
}