题解:Luogu P4516 [JSOI2018]潜入行动

题面

一道 simple 的树形 DP

设状态 (f(i,j,0/1,0/1)) 表示在节点 (i) 作为根节点的子树内 该节点用了 (j) 个监听设备 该节点不放/放 该节点在该子树内被不被监听/被监听 的方案数

[egin{cases} f(u,0,0,0) = 0\ f(u,1,1,0) = 0\ f(u,i+j,0,0) = displaystyle{sum_{(u,v)in T} f(u,i,0,0) imes f(v,j,0,1)} \ f(u,i+j,0,1) = displaystyle{sum_{(u,v)in T} f(u,i,0,1) imes (f(v,j,1,1)+f(v,j,0,1))\ + f(u,i,0,0) imes f(v,j,1,1)}\ \ f(u,i+j,1,0) = displaystyle{sum_{(u,v)in T} f(u,i,1,0) imes(f(v,j,0,1)+f(v,j,0,0))}\ f(u,i+j,1,1) = displaystyle{sum_{(u,v)in T} f(u,i,1,1) imes(f(v,j,0,0)+f(v,j,0,1)+f(v,j,1,0)\ +f(v,j,1,1)) + f(u,i,1,0) imes(f(v,j,1,1)+f(v,j,1,0))}\ end{cases} ]

树形 DP 时,每次只要算 min(size[u]+size[v],k) 的情况就行了,我的代码复杂度是 (mathcal{O}(nlog n imes k))

Code(C++):

#include<bits/stdc++.h>
#define forn(i,s,t) for(int i=(s);i<=(t);++i)
#define form(i,s,t) for(int i=(s);i>=(t);--i)
using namespace std;
typedef long long ll;
const int N = 1e5+3,M = 103,Mod = 1e9+7;
template<typename T> inline T mod(T A) {return A>Mod?A%=Mod:A;}
template<typename T> inline T Dif(T A) {return A>Mod?A-=Mod:A;}
struct List {
	int dir,nxt;
}E[N<<1];
int G[N],cnt;
inline void Add(int u,int v) {
	E[++cnt].dir = v,E[cnt].nxt = G[u],G[u] = cnt;
}
int n,k,sz[N],f[N][M][2][2],g[2][2][M];
void dfs(int u,int fa) {
	sz[u] = 1,f[u][0][0][0] = f[u][1][1][0] = 1;
	for(int s=G[u];s;s=E[s].nxt) {
		int v = E[s].dir;
		if(v == fa) continue ;
		dfs(v,u);
		forn(i,0,min(k,sz[u]+sz[v])) g[0][0][i] = g[0][1][i] = g[1][0][i] = g[1][1][i] = 0;
		forn(i,0,min(k,sz[u])) forn(j,0,min(k-i,sz[v])) {
			g[0][0][i+j] = Dif((ll)g[0][0][i+j]+mod((ll)f[u][i][0][0]*f[v][j][0][1]));
			g[0][1][i+j] = Dif((ll)g[0][1][i+j]+Dif(mod((ll)f[u][i][0][1]*Dif(f[v][j][1][1]+f[v][j][0][1]))+
								mod((ll)f[u][i][0][0]*f[v][j][1][1])));
			g[1][0][i+j] = Dif((ll)g[1][0][i+j]+mod((ll)f[u][i][1][0]*Dif(f[v][j][0][1]+f[v][j][0][0])));
			g[1][1][i+j] = Dif((ll)g[1][1][i+j]+Dif(mod((ll)f[u][i][1][1]*Dif(Dif(f[v][j][0][1]+f[v][j][1][1])+																                        
                                                                                          Dif(f[v][j][1][0]+f[v][j][0][0])))+
								mod((ll)f[u][i][1][0]*Dif(f[v][j][1][1]+f[v][j][1][0]))));
		}
		sz[u] += sz[v];
		forn(i,0,min(k,sz[u])) f[u][i][0][0] = g[0][0][i],f[u][i][0][1] = g[0][1][i],
				       f[u][i][1][0] = g[1][0][i],f[u][i][1][1] = g[1][1][i];
	}
}
int main() {
	scanf("%d%d",&n,&k);
	int u,v;
	forn(i,1,n-1) scanf("%d%d",&u,&v),Add(u,v),Add(v,u);
	dfs(1,0);
	printf("%lld
",Dif((ll)f[1][k][1][1]+f[1][k][0][1]));
	return 0;
}
原文地址:https://www.cnblogs.com/Ax-Dea/p/14083705.html