zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 17F Tree nesting

    来自FallDream的博客,未经允许,请勿转载, 谢谢。


    给你两棵树,一棵比较大(n<=1000),一棵比较小(m<=12) 问第一棵树中有多少个连通子树和第二棵同构。

    答案取膜1e9+7

    考虑在大树中随便选个根,然后在小的那棵那里枚举一个根作为大树中深度最小的节点(注意哈希判同构)

    然后f[x][y]表示大树的x节点作为小树的y节点的方案数。

    如果y是叶子结点,f[x][y]=1

    否则要用x的儿子中的一些节点表示y的所有叶子节点。

    考虑一个状压dp,g[i][s]表示前i个儿子表示了小树的s集合内的节点的方案数,容易转移。

    然后如果y有一些儿子同构,则需要除以个数的阶乘。

    复杂度上界是n*m*2^m 

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<map>
    #define MN 1000
    #define mod 1000000007
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    unsigned long long ha[MN+5];vector<unsigned long long> v[MN+5];map<unsigned long long,int> mp,mp2;
    int n,m,head[MN+5],Head[MN+5],fa[MN+5],cnt=0,f[MN+5][15],F[1<<12],size[MN+5],son[MN+5],q[MN+5],ans=0,now,P[15];
    struct edge{int to,next;}e[MN*3+5];
    inline void R(int&x,int y){x+=y;x>=mod?x-=mod:0;}
    inline void ins(int*H,int f,int t)
    {
        e[++cnt]=(edge){t,H[f]};H[f]=cnt;
        e[++cnt]=(edge){f,H[t]};H[t]=cnt;
    }
    
    int pow(int x,int k)
    {
        int sum=1;
        for(;k;k>>=1,x=1LL*x*x%mod)
            if(k&1) sum=1LL*sum*x%mod;
        return sum;    
    }
    
    void GetHa(int x,int f)
    {
        ha[x]=0;size[x]=1;v[x].clear();fa[x]=f;
        for(int i=Head[x];i;i=e[i].next)
            if(e[i].to!=f) 
            {
                GetHa(e[i].to,x);
                v[x].push_back(ha[e[i].to]);
            }
        son[x]=v[x].size();
        sort(v[x].begin(),v[x].end());
        for(int i=0;i<v[x].size();++i) ha[x]=ha[x]*23333+v[x][i];
        ha[x]=ha[x]*2333+size[x];
    }
    
    void Solve(int x,int fat)
    {
        int num=0;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fat) Solve(e[i].to,x),++num;
        for(int i=1;i<=m;++i)
        {
            if(!son[i]){f[x][i]=1;continue;}    
            if(num<son[i]){f[x][i]=0;continue;}
            for(int k=0;k<1<<son[i];++k)F[k]=0;
            F[0]=1;int top=0;
            for(int j=Head[i];j;j=e[j].next) if(e[j].to!=fa[i]) q[++top]=e[j].to,++mp2[ha[e[j].to]];
            for(int j=head[x];j;j=e[j].next)
                if(e[j].to!=fat)
                {                        
                    for(int s=(1<<top)-1;~s;--s) 
                        for(int k=1;k<=top;++k) if(f[e[j].to][q[k]])
                                if(!(s&(1<<k-1))) R(F[s|(1<<k-1)],1LL*F[s]*f[e[j].to][q[k]]%mod);
                }
            f[x][i]=F[(1<<top)-1];
            for(int j=1;j<=top;++j) 
                if(mp2[ha[q[j]]]) f[x][i]=1LL*f[x][i]*pow(P[mp2[ha[q[j]]]],mod-2)%mod,mp2[ha[q[j]]]=0;
        }
        R(ans,f[x][now]);
    }
    
    int main()
    {
        n=read();P[0]=1;
        for(int i=1;i<=12;++i) P[i]=1LL*P[i-1]*i%mod;
        for(int i=1;i<n;++i) ins(head,read(),read());m=read();
        for(int i=1;i<m;++i) ins(Head,read(),read());
        for(int i=1;i<=m;++i) 
        {
            GetHa(i,0);    
            if(mp[ha[i]]) continue;
            memset(f,0,sizeof(f));mp[ha[i]]=1;
            now=i;Solve(1,0);
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    你会卖掉自己的网上信息吗?大数据可能根本不属于你
    机器学习——TensorFLow实战房价预测
    数据库运作实践三三之歌(秘制口诀)
    1000行MySQL学习笔记,收藏版!
    吐血整理深度学习入门路线及导航【教学视频+大神博客+书籍整理】+【资源页】(2019年已经最后一个月了,你还不学深度学习吗???)
    Ubuntu Snap 简述
    参数传递
  • 原文地址:https://www.cnblogs.com/FallDream/p/cf762f.html
Copyright © 2011-2022 走看看