zoukankan      html  css  js  c++  java
  • [GDOI2018]滑稽子图

    题目链接:【被和谐】

    题目大意:对于一棵树$(V,E)$,对于$S\subset V$,$f(S)$为点集$S$的导出子图的边数。求$\sum_{S\subset V}f(S)^k$

    这里的导出子图说的是,点集为S,边集为$\{(u,v)\in E|u,v\in S\}$的一个子图。


    看到这个$k$次方,马上用斯特林数。

    $$ans=\sum_{S\subset V}f(S)^k=\sum_{i=0}^ki!S(k,i)\sum_{S\subset V}{f(S)\choose i}$$

    然后考虑怎么求后面那个式子。

    这个式子表示在$S$的导出子图里面选$i$条边的方案数,然后就可以树形dp了

    设$dp_{x,s,0/1}$表示在以$x$为根的子树内部,选择$s$条边,$x$是否$\in S$的答案。

    在新加上一个$x$的子树$v$的时候,$S$只有原来只有新的子树的情况直接加上就行。

    还有合在一起的情况,设原来的子树有$j$条边,$v$里面有$k$条边。

    则$$dp[x][j+k][0]+=(dp[v][k][0]+dp[v][k][1])*dp[x][j][0]$$$$dp[x][j+k][1]+=(dp[v][k][0]+dp[v][k][1]+[k\not= 0]dp[v][k-1][1])*dp[x][j][1]$$

    上面那里为什么要加$dp[v][k-1][1]$呢?因为这时$x$和$v$都在点集里,可以选择$(x,v)$这条边。

    注意合在一起的情况还要统计进答案里。

    而且由于会出现贡献到自己的情况,所以要用一个辅助数组来存储。

     1 #include<cstdio>
     2 #include<cstring>
     3 #define Rint register int
     4 using namespace std;
     5 typedef long long LL;
     6 const int N = 100003, mod = 998244353;
     7 int n, m, K, head[N], to[N << 1], nxt[N << 1], size[N];
     8 inline void add(int a, int b){
     9     static int cnt = 0;
    10     to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
    11 }
    12 LL dp[N][13][2], f[13][2], ans[13], S[13][13];
    13 inline void dfs(int x, int fa){
    14     size[x] = 1;
    15     dp[x][0][0] = 0; dp[x][0][1] = 1; ++ ans[0];
    16     for(Rint i = head[x];i;i = nxt[i])
    17         if(to[i] != fa){
    18             dfs(to[i], x);
    19             memcpy(f, dp[x], sizeof f);
    20             for(Rint j = 0;j <= K && j <= size[to[i]];j ++)
    21                 f[j][0] = (f[j][0] + dp[to[i]][j][0] + dp[to[i]][j][1]) % mod;
    22             for(Rint j = 0;j <= K && j <= size[x];j ++)
    23                 for(Rint k = 0;k <= K - j && k <= size[to[i]];k ++){
    24                     LL S = (dp[to[i]][k][0] + dp[to[i]][k][1]) % mod;
    25                     LL s1 = dp[x][j][0] * S % mod, s2 = dp[x][j][1] * (S + (k ? dp[to[i]][k - 1][1] : 0)) % mod;
    26                     f[j + k][0] = (f[j + k][0] + s1) % mod;
    27                     f[j + k][1] = (f[j + k][1] + s2) % mod;
    28                     ans[j + k] = (ans[j + k] + s1 + s2) % mod;
    29                 }
    30             memcpy(dp[x], f, sizeof f);
    31             size[x] += size[to[i]];
    32         }
    33 }
    34 int main(){
    35     scanf("%d%d%d", &n, &m, &K);
    36     for(Rint i = 1;i < n;i ++){
    37         int a, b;
    38         scanf("%d%d", &a, &b);
    39         add(a, b); add(b, a);
    40     }
    41     dfs(1, 0);
    42     S[0][0] = 1;
    43     for(Rint i = 1;i <= K;i ++)
    44         for(Rint j = 1;j <= i;j ++)
    45             S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * j) % mod;
    46     LL fac = 1, res = 0;
    47     for(Rint i = 1;i <= K;i ++){
    48         fac = fac * i % mod;
    49         res = (res + fac * S[K][i] % mod * ans[i] % mod) % mod;
    50     }
    51     printf("%lld", res);
    52 }
  • 相关阅读:
    scrapy爬虫框架
    运用GRASP原则来做uml交互类图-------pos机实例
    csv文件读取
    文件编码解读
    smtp模块使用
    csv模块简单使用
    用Beautifulsoup 来爬取贴吧图片
    批处理命令——set
    bat批处理教程之for的/f参数
    docker 下 alpine 镜像设置时区的有效办法
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/10500323.html
Copyright © 2011-2022 走看看