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;
}
posted @ 2023-03-24 16:41  FxorG  阅读(43)  评论(0编辑  收藏  举报