• 神经网络


    经典的小球模型。
    显然状压是过不了后面的点的。
    考虑挖掘哈密尔顿回路的性质,它的性质是:在遍历某棵树时,在这棵树上走过的轨迹必须是一条链,遍历完之后要跳到另一颗树。
    所以哈密尔顿回路实际上由若干条链组成。
    设链(i)在树(x)中,则相邻的链不能在同一棵树。
    这是个经典的问题(小球容斥模型)。
    先考虑求出(f_{i,j})表示树(i)被划分成(j)条链的方案数。
    这可以通过dp求出。
    (g_{i,j,k})表示(i)子树中选出(j)条链,(i)向子树连出(k)条边。
    可以树形背包求。
    注意到对于长度(>1)的链(设开头结尾为(a,b)),进入/出它的方案有(2)类:(a)(b)出,(b)(a)出,所以答案要(*=2)
    先考虑序列问题。
    考虑求出每棵树的egf(就是每种"链小球"的egf)。设树被划分为(k)条链。
    公式:(=f_{i,k} sumlimits_{j=1}^k (-1)^{(k-j)} inom{k-1}{j-1} frac{x^j}{j!})
    原因:(f_{i,k})就是选出(k)条链的方案。
    考虑容斥。容斥有多少条链是必须接在一起的。
    这些链可以被缩成一个小球。
    ((-1)^{(k-j)})表示容斥系数。
    如果某些链被接在一起且它们相邻,把这两条链(小球)之间连一条边。
    (inom{k-1}{j-1})表示在当前链序列中选择(j)个空位,插入边的方案。
    对于每个(k)求和就是整棵树的生成函数。
    但是还要考虑处理环的问题。
    考虑钦定一颗树,使第一条链一定来自这棵树。
    由于第一条链必须在第一位,生成函数为(sumlimits_{k=1}^{k_i} frac{f_{i,k}}{k} sumlimits_{j=1}^k (-1)^{(k-j)} inom{k-1}{j-1} frac{x^{j-1}}{(j-1)!})
    前面要除以(k)是因为当前树可能有(k)条链作为起始位置,导致算重(k)次。
    但是发现第一棵树不能有相邻的两条链,所以第一颗树的生成函数要减去(sumlimits_{k=1}^{k_i} frac{f_{i,k}}{k} sumlimits_{j=1}^k (-1)^{(k-j)} inom{k-1}{j-1} frac{x^{j-2}}{(j-2)!})
    最后把所有树的生成函数卷积(暴力即可)就是答案。
    时间复杂度还是(O(n^2))
    证明:设我们要卷积的多项式大小为(a_1,a_2...a_k)
    构造一颗树:把(a_i)裂成(i)个点连成链,然后把(a_{i-1})的链尾连向(a_i)的链头。
    如果倒着进行卷积,时间复杂度一定低于于在这条链上进行树形背包的时间复杂度。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define mo 998244353
    #define N 5010
    int t[N],jc[N],ij[N],iv[N],h[N],v[N*2],nxt[N*2],ec,m,sz[N],ans[N],va,tp[N][3],sc[N],f[N][N][3],c[N],i2;
    int cc(int y,int x){
    	if(y<0||x<0||y<x)
    		return 0;
    	return jc[y]*ij[x]%mo*ij[y-x]%mo;
    }
    void add(int x,int y){
    	v[++ec]=y;
    	nxt[ec]=h[x];
    	h[x]=ec;
    }
    void ml(int *a,int *b,int *c,int d,int e){
    	for(int i=0;i<=d+e;i++)
    		t[i]=0;
    	for(int i=0;i<=d;i++)
    		for(int j=0;j<=e;j++)
    			t[i+j]=(t[i+j]+a[i]*b[j]%mo)%mo;
    	for(int i=0;i<=d+e;i++)
    		c[i]=t[i];
    }
    int qp(int x,int y){
    	int r=1;
    	for(;y;y>>=1,x=x*x%mo)
    		if(y&1)
    			r=r*x%mo;
    	return r;
    }
    void dfs(int x,int fa){
    	sz[x]=f[x][1][0]=1;
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa){
    			int y=v[i];
    			dfs(y,x);
    			for(int j=1;j<=sz[y];j++){
    				int tv=(f[y][j][0]+f[y][j][1]+f[y][j][2])%mo;
    				for(int k=1;k<=sz[x];k++){
    					tp[j+k][0]=(tp[j+k][0]+tv*f[x][k][0]%mo)%mo;
    					tp[j+k][1]=(tp[j+k][1]+tv*f[x][k][1]%mo)%mo;
    					tp[j+k][2]=(tp[j+k][2]+tv*f[x][k][2]%mo)%mo;
    					tp[j+k-1][1]=(tp[j+k-1][1]+f[x][k][0]*(f[y][j][1]+2*f[y][j][0]%mo)%mo)%mo;
    					tp[j+k-1][2]=(tp[j+k-1][2]+f[x][k][1]*(i2*f[y][j][1]%mo+f[y][j][0])%mo)%mo;
    				}
    			}
    			sz[x]+=sz[y];
    			for(int j=0;j<=sz[x];j++){
    				f[x][j][0]=tp[j][0];
    				f[x][j][1]=tp[j][1];
    				f[x][j][2]=tp[j][2];
    				tp[j][0]=tp[j][1]=tp[j][2]=0;
    			}
    		}
    }
    signed main(){
    	i2=(mo+1)/2;
    	jc[0]=ij[0]=1;
    	for(int i=1;i<N;i++){
    		jc[i]=jc[i-1]*i%mo;
    		ij[i]=qp(jc[i],mo-2);
    		iv[i]=qp(i,mo-2);
    	}
    	int sn=0;
    	ans[0]=1;
    	scanf("%lld",&m);
    	for(int i=m;i;i--){
    		int n;
    		scanf("%lld",&n);
    		for(int j=1;j<n;j++){
    			int x,y;
    			scanf("%lld%lld",&x,&y);
    			add(x,y);
    			add(y,x);
    		}
    		dfs(1,0);
    		for(int j=1;j<=n;j++)
    			c[j]=(f[1][j][0]+f[1][j][1]+f[1][j][2])%mo*jc[j]%mo;
    		for(int j=1;j<=n;j++){
    			int va=0;
    			for(int k=j;k<=n;k++){
    				int bp=1,ii=1;
    				if(i==1)
    					ii=iv[k];
    				if((k-j)&1)
    					bp=mo-1;
    				va=(va+bp*c[k]%mo*cc(k-1,j-1)%mo*ii%mo+mo)%mo;
    			}
    			if(i==1){
    				sc[j-1]=va;
    				if(j>=2)
    					sc[j-2]=(sc[j-2]-va+mo)%mo;
    			}
    			else
    				sc[j]=va;
    		}
    		for(int j=0;j<=n;j++)
    			sc[j]=sc[j]*ij[j]%mo;
    		ml(ans,sc,ans,sn,n);
    		sn+=n;
    		for(int j=1;j<=ec;j++)
    			nxt[j]=v[j]=0;
    		for(int j=1;j<=n;j++){
    			h[j]=sc[j]=c[j]=0;
    			for(int k=1;k<=n;k++)
    				f[j][k][0]=f[j][k][1]=f[j][k][2]=0;
    		}
    		ec=0;
    	}
    	for(int i=1;i<=sn;i++)
    		va=(va+jc[i]*ans[i])%mo;
    	printf("%lld",va);
    }
    
  • 相关阅读:
    MySQL简单实现多字段模糊查询【转】
    PHP检测URL格式是否正确域名地址是否有效【转】
    php如何判断IP为有效IP地址【转】
    PHP isset() 函数使用【转】
    php生成唯一随机码【转】
    php判断一个值是否在数组中【转】
    Win10系统gpedit.msc文件找不到,如何解决【转】
    B
    【金色】种瓜得瓜,种豆得豆 Gym
    J
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14441870.html
Copyright © 2020-2023  润新知