[JSOI2018]潜入行动

[JSOI2018]潜入行动

题目大意:

一棵(n(nle10^5))个结点的树,在一些点上安装(k(klemin(n,100)))个装置。每个装置可以控制所有与安装位置相邻的结点(不包括本身)。每个点可以安装至多一个装置。问有多少种方案恰好用完(k)个装置,使得所有的结点都被控制。

思路:

树形DP。(f[i][j][0/1][0/1])表示以(i)为根的子树内安装了(j)个装置,(i)本身是否安装,(i)是否被控制。手动讨论转移:

f[x][j+k][0][0]+=f[y][k][0][1]*g[j][0][0]
f[x][j+k][0][1]+=f[y][k][0][1]*g[j][0][1]
f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][1]
f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][0]
f[x][j+k][1][0]+=f[y][k][0][0]*g[j][1][0]
f[x][j+k][1][0]+=f[y][k][0][1]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][0][0]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][0][1]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][1]

需要卡常数和内存。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
typedef long long int64;
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int N=1e5+1,M=101,mod=1e9+7;
int m,size[N],f[N][M][2][2],g[M][2][2],h[N];
struct Edge {
	int to,next;
};
Edge e[N<<1];
inline void add_edge(const int &u,const int &v) {
	e[++h[0]]=(Edge){v,h[u]};h[u]=h[0];
	e[++h[0]]=(Edge){u,h[v]};h[v]=h[0];
}
void dfs(const int &x,const int &par) {
	f[x][0][0][0]=f[x][1][1][0]=size[x]=1;
	for(unsigned i=h[x];i;i=e[i].next) {
		const int &y=e[i].to;
		if(y==par) continue;
		dfs(y,x);
		for(register int j=std::min(size[x],m);~j;j--) {
			g[j][0][0]=f[x][j][0][0];
			g[j][0][1]=f[x][j][0][1];
			g[j][1][0]=f[x][j][1][0];
			g[j][1][1]=f[x][j][1][1];
			f[x][j][0][0]=f[x][j][0][1]=f[x][j][1][0]=f[x][j][1][1]=0;
		}
		for(register int j=std::min(size[x],m);~j;j--) {
			for(register int k=std::min(size[y],m-j);~k;k--) {
				(f[x][j+k][0][0]+=(int64)f[y][k][0][1]*g[j][0][0]%mod)%=mod;
				(f[x][j+k][0][1]+=((int64)f[y][k][1][1]*(g[j][0][1]+g[j][0][0])+(int64)f[y][k][0][1]*g[j][0][1])%mod)%=mod;
				(f[x][j+k][1][0]+=(int64)(f[y][k][0][0]+f[y][k][0][1])*g[j][1][0]%mod)%=mod;
				(f[x][j+k][1][1]+=((int64)(f[y][k][1][0]+f[y][k][1][1])*g[j][1][0]+((int64)f[y][k][0][0]+f[y][k][0][1]+f[y][k][1][0]+f[y][k][1][1])%mod*g[j][1][1])%mod)%=mod;
			}
		}
		size[x]+=size[y];
	}
}
int main() {
	const int n=getint();m=getint();
	for(register int i=1;i<n;i++) {
		add_edge(getint(),getint());
	}
	dfs(1,0);
	printf("%d
",(f[1][m][0][1]+f[1][m][1][1])%mod);
	return 0;
}
原文地址:https://www.cnblogs.com/skylee03/p/9169146.html