题解:Luogu P4516 [JSOI2018]潜入行动
一道 simple 的树形 DP
设状态 \(f(i,j,0/1,0/1)\) 表示在节点 \(i\) 作为根节点的子树内 该节点用了 \(j\) 个监听设备 该节点不放/放 该节点在该子树内被不被监听/被监听 的方案数
\[\begin{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)\times f(v,j,0,1)} \\
\ f(u,i+j,0,1) = \displaystyle{\sum_{(u,v)\in T} f(u,i,0,1)\times (f(v,j,1,1)+f(v,j,0,1))\\
\ + f(u,i,0,0)\times f(v,j,1,1)}\\
\ \\
\ f(u,i+j,1,0) = \displaystyle{\sum_{(u,v)\in T} f(u,i,1,0)\times(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)\times(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)\times(f(v,j,1,1)+f(v,j,1,0))}\\
\end{cases}
\
\]
树形 DP 时,每次只要算 min(size[u]+size[v],k)
的情况就行了,我的代码复杂度是 \(\mathcal{O}(n\log n\times 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\n",Dif((ll)f[1][k][1][1]+f[1][k][0][1]));
return 0;
}