[CF735E/736C]Ostap and Tree

题目大意:
  一个$n(n\le100)$个点的树,将一些点染成黑点,求满足每个点到最近黑点的距离$\le k(k\le\min(20,n-1))$的方案数。

思路:
  树形DP。
  用$f[i][j]$表示$i$的子树中离$i$最近黑点的距离为$j$,且距离超过$j$的点都被满足的方案数。转移时新建一个临时数组$tmp$保存转移后的$f[x]$。设$y$是$x$的子结点,枚举$f[x][i]$和$f[y][j]$,转移如下:
    1.若$i+j\le2k$,则此时$\min(i,j+1)\le k$,对于长度为$i+j+1$的链上的所有点都可以找到一边距离$\le k$,因此状态合并以后是合法状态,转移$tmp[\min(i,j+1)]+=f[x][i]\times f[y][j]$;
    2.若$i+j>2k$,则此时$\max(i,j+1)>k$,链上肯定会存在一些点两边都够不到,转移$tmp[\max(i,j+1)]+=f[x][i]\times f[y][j]$。
  初始状态$f[x][0]=1$,表示不考虑子树内的情况,选择自己的方案数为$1$;$f[x][k+1]=1$,表示自己本身不满足,但子结点都被满足的情况,主要是方便转移。
  答案为$\sum_{i<=k}f[root][i]$。
  时间复杂度$O(nk^2)$。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 #include<forward_list>
 5 typedef long long int64;
 6 inline int getint() {
 7     register char ch;
 8     while(!isdigit(ch=getchar()));
 9     register int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return x;
12 }
13 const int N=101,K=41,mod=1e9+7;
14 int k,f[N][K],tmp[K];
15 std::forward_list<int> e[N];
16 inline void add_edge(const int &u,const int &v) {
17     e[u].push_front(v);
18     e[v].push_front(u);
19 }
20 void dfs(const int &x,const int &par) {
21     f[x][0]=f[x][k+1]=1;
22     for(int &y:e[x]) {
23         if(y==par) continue;
24         dfs(y,x);
25         std::fill(&tmp[0],&tmp[k*2]+1,0);
26         for(register int i=0;i<=k*2;i++) {
27             for(register int j=0;j<=k*2;j++) {
28                 (tmp[i+j<=k*2?std::min(i,j+1):std::max(i,j+1)]+=(int64)f[x][i]*f[y][j]%mod)%=mod;
29             }
30         }
31         std::copy(&tmp[0],&tmp[k*2]+1,f[x]);
32     }
33 }
34 int main() {
35     const int n=getint();k=getint();
36     for(register int i=1;i<n;i++) {
37         add_edge(getint(),getint());
38     }
39     dfs(1,0);
40     int ans=0;
41     for(register int i=0;i<=k;i++) {
42         (ans+=f[1][i])%=mod;
43     }
44     printf("%d\n",ans);
45     return 0;
46 }

 

posted @ 2018-05-04 10:27  skylee03  阅读(221)  评论(0编辑  收藏  举报