• [CSAcademy]Connected Tree Subgraphs


    题目大意:
      给你一棵n个结点的树,求有多少种染色方案,使得染色过程中染过色的结点始终连成一块。

    思路:
      树形DP。
      设f[x]表示先放x时,x的子树中的染色方案数,y为x的子结点。
      则f[x]=prod{f[y]}*(size[x]-1)!/prod{size[y]}。
      现在我们改变f[x]的含义,让其表示先放x时,整棵子树的方案数。
      考虑根的转移对答案做出的贡献。
      假设我们从x转移到y,那么就要把y从x中剔除,
      设剔除y后的f[x]为t,则t=f[x]*size[y]*(size[x]-1-size[y])!/f[y]/(size[x]-1)!。
      这是我们要把x子树中的方案数,也就是t算入f[y]中。
      f[y]=f[y]*t*(n-1)!/(size[y]-1)!/(n-1-size[y])!。
      把t代入,发现f[y]=f[x]*(n-1-size[y])!*size[y]!/(size[y]-1)!/(n-size[y])!。
      时间复杂度O(n)。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const int N=100001;
    13 const int mod=1e9+7;
    14 std::vector<int> e[N];
    15 inline void add_edge(const int &u,const int &v) {
    16     e[u].push_back(v);
    17     e[v].push_back(u);
    18 }
    19 void exgcd(const int &a,const int &b,int &x,int &y) {
    20     if(!b) {
    21         x=1;
    22         y=0;
    23         return;
    24     }
    25     exgcd(b,a%b,y,x);
    26     y-=a/b*x;
    27 }
    28 inline int inv(const int &x) {
    29     int ret,tmp;
    30     exgcd(x,mod,ret,tmp);
    31     return (ret%mod+mod)%mod;
    32 }
    33 int f[N],fact[N],size[N];
    34 void dfs(const int &x,const int &par) {
    35     f[x]=size[x]=1;
    36     for(unsigned i=0;i<e[x].size();i++) {
    37         const int &y=e[x][i];
    38         if(y==par) continue;
    39         dfs(y,x);
    40         size[x]+=size[y];
    41         f[x]=(int64)f[x]*f[y]%mod*inv(fact[size[y]])%mod;
    42     }
    43     f[x]=(int64)f[x]*fact[size[x]-1]%mod;
    44 }
    45 void move(const int &x,const int &par) {
    46     for(unsigned i=0;i<e[x].size();i++) {
    47         const int &y=e[x][i];
    48         if(y==par) continue;
    49         f[y]=(int64)f[x]*fact[size[1]-1-size[y]]%mod*fact[size[y]]%mod*inv(fact[size[y]-1])%mod*inv(fact[size[1]-size[y]])%mod;
    50         move(y,x);
    51     } 
    52 }
    53 int main() {
    54     const int n=getint();
    55     fact[0]=1;
    56     for(register int i=1;i<n;i++) {
    57         fact[i]=(int64)fact[i-1]*i%mod;
    58     }
    59     for(register int i=1;i<n;i++) {
    60         add_edge(getint(),getint());
    61     }
    62     int ans=0;
    63     dfs(1,0);
    64     move(1,0);
    65     for(register int i=1;i<=n;i++) {
    66         ans=(ans+f[i])%mod;
    67     }
    68     printf("%d
    ",ans);
    69     return 0;
    70 }
  • 相关阅读:
    《临江仙·滚滚长江东逝水》
    .net Core Newtonsoft.Json 解析巨坑之注释影响代码
    C# 后端post请求帮助类
    鼠标点击事件
    常用Windows 消息列表
    WinUser.h>>>OnMessage事件
    Jellyfin流媒体服务器搭建和一些小坑
    ios开发遇到的问题
    节省你的时间,用AHK实现随机打开文件
    一些简单的AHK脚本提升电脑使用体验
  • 原文地址:https://www.cnblogs.com/skylee03/p/8124765.html
Copyright © 2020-2023  润新知