[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;
}