题解 P4516 【[JSOI2018]潜入行动】

_lgswdn

2020-05-11 16:41:28

Solution

## 部分分: $\texttt{Subtask1 10pts }n\le 20$ 枚举每个点装不装监听器,然后判断是否可行 $\texttt{Subtask2 10pts }k\le 10$ $k$ 很小,在随机情况下(也同样是数据)无法覆盖整个树,直接输出 $0$。 $\texttt{Subtask3 10pts }$ 整个树是链 如果 $k$ 小于 $n-2$,那么无法覆盖住这个树,输出 $0$ 所以如果我在考场上可以拿 $30$ 分…… --- ## 正解: 显然这是个树形背包,我们可以用树形背包的常见套路做。$f(u,x,0/1,0/1)$ 代表第 $u$ 个节点子树用 $x$ 个监听器,$u$ 装/不装监听器,$u$有/没有被覆盖。 (以下 $v$ 代表 $u$ 的儿子) --- 对于 $f(u,x,0,0)$,由于自己不能被覆盖,所以 $v$ 就不能安装。由于自己不能安装,所以 $v$ 一定需要安装(否则就没有其他人去覆盖这个节点了)。 由于这个是乘法原理算种类数,所以应该是乘起来。 $$ f(u,i+j,0,0)=f(u,i,0,0)\times f(v,j,0,1) $$ 对于 $f(u,x,0,1)$,由于自己被覆盖,所以 $v$ 中至少有一个必须安装。 那么可以转移到这个状态的 $f(u)$ 应该有 $f(u,x,0,0)$ 和 $f(u,x,0,1)$,可以显然推得: $$ f(u,i+j,0,1)=f(u,i,0,0)\times f(v,j,1,1)+f(u,i,0,1)\times f(v,j,0/1,1) $$ 对于 $f(u,x,1,0)$,由于自己没有被覆盖,所以 $v$ 就不能安装。由于自己安装了,所以 $v$ 可以覆盖或者不覆盖。 $$ f(u,i+j,1,0)=f(u,i,1,0)\times f(v,j,0,0/1) $$ 对于 $f(u,x,1,1)$,由于自己被覆盖了,所以 $v$ 中至少有一个安装。可以转移到这个状态的 $f(u)$ 有 $f(u,x,1,0)$ 和 $f(u,x,1,1)$。 由于自己安装了,所 $v$ 可以覆盖或者不覆盖。 $$ f(u,i+j,1,1)=f(u,i,1,0)\times f(v,j,1,0/1)+f(u,i,1,1)\times f(v,j,0/1,0/1) $$ 初始化: $f(u,0,0,0)=f(u,1,1,0)=1$ --- ## 代码&细节 推完式子就可以写代码了(转移方程长得有点难受)。 然后这题强制用 int 然后操作转 longlong 很杀人。 我对出题人卡空间的行为感到**非常不满**( ```foin(x,y)``` 函数代表两数相加并取模(在 int 转 longlong 操作中很实用)。 ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+3; const ll mod=1000000007; struct edge{int to,nxt;}e[N*2]; int hd[N],tot; void add(int u,int v){e[++tot]=(edge){v,hd[u]},hd[u]=tot;} int n,k; int foin(ll q,ll p){return (q+p)>mod?1ll*q+p-mod:q+p;} int sz[N],f[N][103][2][2],t[103][2][2]; //树形背包常用的3个数组 void dfs(int u,int fa){ f[u][0][0][0]=f[u][1][1][0]=sz[u]=1; for(register int p=hd[u],v;p;p=e[p].nxt) if((v=e[p].to)!=fa){ dfs(v,u); for(register int i=0;i<=min(sz[u],k);i++) for(register int j=0;j<2;j++) for(register int k=0;k<2;k++) t[i][j][k]=f[u][i][j][k], f[u][i][j][k]=0; for(register int i=0;i<=min(sz[u],k);i++){ for(register int j=0;j<=min(sz[v],k-i);j++){ f[u][i+j][0][0]=foin(f[u][i+j][0][0],1ll*t[i][0][0]*f[v][j][0][1]%mod); f[u][i+j][0][1]=foin(f[u][i+j][0][1],(1ll*t[i][0][0]*f[v][j][1][1]+1ll*t[i][0][1]*(1ll*f[v][j][0][1]+f[v][j][1][1]))%mod); f[u][i+j][1][0]=foin(f[u][i+j][1][0],1ll*t[i][1][0]*(1ll*f[v][j][0][0]+f[v][j][0][1])%mod); f[u][i+j][1][1]=foin(f[u][i+j][1][1],foin((1ll*t[i][1][0]*(1ll*f[v][j][1][0]+f[v][j][1][1])%mod) ,1ll*t[i][1][1]*(1ll*f[v][j][0][0]+f[v][j][0][1]+f[v][j][1][0]+f[v][j][1][1])%mod)); } } sz[u]+=sz[v]; } } int main(){ scanf("%d%d",&n,&k); for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u); dfs(1,0); printf("%lld",1ll*(f[1][k][0][1]+f[1][k][1][1])%mod); return 0; } ```