zoukankan      html  css  js  c++  java
  • CF917D Stranger Trees

    题目传送门

    分析:
    我们设恰好(k)条边不重复的方案数为(f(k))
    再设钦定(n-k-1)条边与原来树上的边重合,剩下的边自由连接成树的方案数(g(k))
    于是得到一个公式:

    [g(k)=sum_{i=0}^{k}inom{k}{i}f(i) ]

    意义为枚举剩下的(K)条边有哪些不重合
    于是我们二项式反演:

    [f(k)=sum_{i=0}^{k}(-1)^{k-i}inom{k}{i}g(i) ]

    知道了(g)我们就可以(O(n^2))(f)
    考虑(g(k))之中会有(k+1)个连通块,那么生成树的方案数为

    [n^{k-1}prod_{i=1}^{k+1}a_i ]

    其中(a_i)表示每个连通块的大小,即在此连通块里选择一个点向其他连通块连边
    我们想知道(prod_{i=1}^{k+1}a_i)在所有情况下的总和
    考虑(DP)
    (f[u][i][0/1])表示在(u)为根的子树下,已经钦定(sz[u]-i-1)条边,(u)所在连通块是否已选择了一个点
    列出(DP)式子
    (g[i][0/1])为传递给下一次(DP)的临时变量
    (g[j+k][0]=f[u][j][0]*f[v][k][0])钦定这条父子边,(u,v)属于同一连通块未被选择
    (g[j+k][1]=f[u][j][0]*f[v][k][1]+f[u][j][1]*f[v][k][0])钦定这条父子边,(u,v)属于同一连通块其中被选择
    (g[j+k+1][0]=f[u][j][0]*f[v][k][1])不钦定这条父子边,(u,v)不属于同一连通块,(v)必须被选择,(u)继承原来的状态
    (g[j+k+1][1]=f[u][j][1]*f[v][k][1])不钦定这条父子边,(u,v)不属于同一连通块,(v)必须被选择,(u)继承原来的状态
    总复杂度为(O(n^2))

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<iostream>
    #include<map>
    #include<bitset>
    #include<string>
    
    #define maxn 205
    #define MOD 1000000007
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n;
    int sz[maxn];
    int fir[maxn],nxt[maxn<<1],to[maxn<<1],cnt;
    int f[maxn][maxn][2],g[maxn][2],ans[maxn],C[maxn][maxn];
    
    inline int upd(int x){return x<MOD?x:x-MOD;}
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    inline void newnode(int u,int v)
    {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
    inline void dfs(int u,int fa)
    {
    	sz[u]=f[u][0][0]=f[u][0][1]=1;
    	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa)
    	{
    		int v=to[i];dfs(v,u);
    		for(int j=0;j<=sz[u]+sz[v];j++)g[j][0]=g[j][1]=0;
    		for(int j=0;j<=sz[u];j++)for(int k=0;k<=sz[v];k++)
    		{
    			g[j+k][0]=(g[j+k][0]+1ll*f[u][j][0]*f[v][k][0])%MOD;
    			g[j+k][1]=(g[j+k][1]+1ll*f[u][j][0]*f[v][k][1]+1ll*f[u][j][1]*f[v][k][0])%MOD;
    			g[j+k+1][0]=(g[j+k+1][0]+1ll*f[u][j][0]*f[v][k][1])%MOD;
    			g[j+k+1][1]=(g[j+k+1][1]+1ll*f[u][j][1]*f[v][k][1])%MOD;
    		}
    		sz[u]+=sz[v];
    		for(int j=0;j<=sz[u];j++)f[u][j][0]=g[j][0],f[u][j][1]=g[j][1];
    	}
    }
    
    int main()
    {
    	n=getint();
    	for(int i=1;i<n;i++)
    	{
    		int u=getint(),v=getint();
    		newnode(u,v),newnode(v,u);
    	}
    	for(int i=0;i<=n;i++)
    	{
    		C[i][0]=1;
    		for(int j=1;j<=i;j++)C[i][j]=upd(C[i-1][j-1]+C[i-1][j]);
    	}
    	dfs(1,1);
    	ans[0]=1;
    	for(int i=1;i<n;i++)ans[i]=1ll*f[1][i][1]*ksm(n,i-1)%MOD;
    	for(int i=0;i<n;i++)for(int j=0;j<i;j++)ans[i]=upd(ans[i]-1ll*C[n-1-j][i-j]*ans[j]%MOD+MOD);
    	for(int i=n-1;~i;i--)printf("%d ",ans[i]);
    }
    

  • 相关阅读:
    Unix环境高级编程—进程关系
    如何学习CCIE
    Unix环境高级编程—进程控制(三)
    Unix环境高级编程—进程控制(二)
    _THROW 何解?
    Unix高级环境编程—进程控制(一)
    ifndef/define/endif 和 #ifdef 、#if 作用和用法
    内存MCE错误导致暴力扩充messages日志 以及chattr记录
    Intellij IDEA的安装和激活
    Xshell和Xftp间隔一段时间不操作就自动断开连接?
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13024529.html
Copyright © 2011-2022 走看看