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 }
D1T1

相关文章: