D1T1:潜入行动
裸的树上DP。f[i][j][0/1][0/1]表示以i为根的子树放j个设备,根有没有放,根有没有被子树监听,的方案数。转移显然。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=100010,mod=1e9+7; 8 ll tmp[110][2][2]; 9 int n,k,cnt,u,v,sz[N],dp[N][110][2][2],h[N],to[N<<1],nxt[N<<1]; 10 11 void ins(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 12 void add(int &x,ll y){ if (x+y>=mod) x=x+y-mod; else x=x+y; } 13 14 void dfs(int x,int fa){ 15 sz[x]=1; dp[x][1][1][0]=1; dp[x][0][0][0]=1; 16 for (int i=h[x]; i; i=nxt[i]){ 17 int v=to[i]; 18 if (v==fa) continue; 19 dfs(v,x); 20 int tx=min(k,sz[x]),tv=min(k,sz[v]); 21 rep(j,0,tx) rep(a,0,1) rep(b,0,1) 22 tmp[j][a][b]=dp[x][j][a][b],dp[x][j][a][b]=0; 23 rep(j,0,tx){ 24 for(int a=0; a<=tv && j+a<=k; a++){ 25 add(dp[x][j+a][0][0],tmp[j][0][0]*dp[v][a][0][1]%mod); 26 add(dp[x][j+a][0][1],(tmp[j][0][0]*dp[v][a][1][1]+tmp[j][0][1]*(dp[v][a][0][1]+dp[v][a][1][1]))%mod); 27 add(dp[x][j+a][1][0],tmp[j][1][0]*(dp[v][a][0][0]+dp[v][a][0][1])%mod); 28 add(dp[x][j+a][1][1],(tmp[j][1][0]*(dp[v][a][1][0]+dp[v][a][1][1])+tmp[j][1][1]*(dp[v][a][0][0]+dp[v][a][1][0])+tmp[j][1][1]*(dp[v][a][0][1]+dp[v][a][1][1]))%mod); 29 } 30 } 31 sz[x]+=sz[v]; 32 } 33 } 34 35 int main(){ 36 freopen("action.in","r",stdin); 37 freopen("action.out","w",stdout); 38 scanf("%d%d",&n,&k); 39 rep(i,2,n) scanf("%d%d",&u,&v),ins(u,v),ins(v,u); 40 dfs(1,-1); 41 printf("%d\n",(dp[1][k][1][1]+dp[1][k][0][1])%mod); 42 return 0; 43 }