zoukankan      html  css  js  c++  java
  • AtCoder [ARC101E] Ribbons on Tree

    $O(n^3)$ 的暴力 $ ext{DP}$ 比较好想,但是貌似无法优化了

    考虑既然有如此强的限制,要求每一条边都被覆盖过,可以尝试使用容斥

    设 $E$ 为没有覆盖到的边集, $F(E)$ 为 $E$ 中的边没有覆盖到(其他不管)的整棵树的方案数

    于是用 $E$ 相当于将这棵树分割成了许多联通块,每个联通块里面只能选自己联通块的,那么每个联通块的方案数为

    $h(size)=(size-1) imes (size-3) imes ... imes 3 imes 1$ (前提是 $2 mid size$ ,不然方案数显然为 $0$ )

    于是我们可以换种方式 $ ext{DP}$ 

    设 $f_{i,j}$ 为以 $i$ 为根的子树内 $i$ 所在的联通块大小为 $j$ 的方案数(不删掉 $i$ 所在的联通块)

    所以转移就按容斥一样转移,如果删掉一棵子树,那就要减去删掉的方案数(差不多是这个意思),否则直接加上方案数

    最后答案显然就是

    $sumlimits_{i=2}^n f_{1,i} imes h(i)$

    $code$ :

    #include<cstdio>
    #include<cctype>
    
    #define maxn 5555
    #define mod 1000000007
    
    template<class T>
    
    inline T read(){
        T r=0,f=0;
        char c;
        while(!isdigit(c=getchar()))f|=(c=='-');
        while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar();
        return f?-r:r;
    }
    
    template<class T>
    
    inline T min(T a,T b){
        return a<b?a:b;
    }
    
    struct E{
        int v,nxt;
        E() {}
        E(int v,int nxt):v(v),nxt(nxt) {}
    }e[maxn<<1];
    
    int n,s_e,head[maxn],size[maxn];
    
    long long ans,h[maxn],g[maxn],f[maxn][maxn];
    
    inline void a_e(int u,int v){
        e[++s_e]=E(v,head[u]);
        head[u]=s_e;
    }
    
    void dfs(int u,int fa){
        f[u][1]=1;
        size[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(v==fa)continue;
            dfs(v,u);
            for(int j=1;j<=size[u]+size[v];j++)g[j]=0;
            for(int j=1;j<=size[u];j++)
                for(int k=1;k<=size[v];k++){
                    (g[j]+=(mod-f[u][j]*f[v][k]%mod*h[k])%mod)%=mod;//删掉v这棵子树里的,所以要减去
                    (g[j+k]+=f[u][j]*f[v][k]%mod)%=mod;//不然直接累加
                }
            for(int j=1;j<=size[u]+size[v];j++)f[u][j]=g[j];
            size[u]+=size[v];
        }
    }
    
    int main(){
        n=read<int>();
        for(int i=1;i<n;i++){
            int u=read<int>(),v=read<int>();
            a_e(u,v),a_e(v,u);
        }
        h[0]=1;
        for(int i=2;i<=n;i+=2)
            h[i]=h[i-2]*(i-1)%mod;
        dfs(1,0);
        ans=0;
        for(int i=2;i<=n;i+=2)
            (ans+=f[1][i]*h[i]%mod)%=mod;
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    今日头条、Face++开发岗面经
    美团offer面经
    成都百度测试开发一二面面经
    美团四面面经
    久邦数码(3G门户)面试
    58 面试
    好未来提前批
    百度提前批
    新浪面经
    Java Programs
  • 原文地址:https://www.cnblogs.com/wyzwyz/p/14025235.html
Copyright © 2011-2022 走看看