luogu P4233

题目链接

题意

从有哈密尔顿回路的竞赛图中随机选取一张,图上哈密尔顿回路数的期望是多少,如果没有这样的竞赛图,输出-1,mod 998244353

数据

给定n,表示竞赛图的点数,需要对从1到n的每个值都计算一次
n 1 e 5 n\le 1e5

解法

考虑知道n个点的竞赛图中总共有多少条哈密尔顿回路,首先需要一个n个点的环排列,方案数是 ( n 1 ) ! (n-1)! ,然后剩下来的边随便连,这是 2 n ( n 1 ) / 2 n 2^{n*(n-1)/2-n} ,这个是每条边有两个方向,然后需要知道n个点的竞赛图中有多少个图存在哈密尔顿回路,设为f[n]
那么答案就是 ( n 1 ) ! 2 n ( n 1 ) / 2 n f [ n ] \frac{(n-1)!*2^{n*(n-1)/2-n}}{f[n]}

现在的问题是求f[n]的值,考虑用总数减去不合法的方案数:
f [ n ] = 2 C ( n , 2 ) i = 1 n 1 f [ i ] C ( n , i ) 2 C ( n i , 2 ) f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*C(n,i)*2^{C(n-i,2)}
这个式子的前半部分是n个点的竞赛图总数,后面计算的方式是枚举一号点所在的合法联通块的大小,此时为了保证这个方案不合法,其他点向这个联通块连边的方式是固定的,其它的点之间可以随便连。

观察f[n]的式子,由于里面出现了组合数,考虑EGF,把组合数拆开:
f [ n ] = 2 C ( n , 2 ) i = 1 n 1 f [ i ] n ! i ! ( n i ) ! 2 C ( n i , 2 ) f[n]=2^{C(n,2)}-\sum_{i=1}^{n-1}f[i]*\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
我们把 1 i ! \frac{1}{i!} f [ i ] f[i] 放到一起, 1 ( n i ! ) \frac{1}{(n-i!)} 2 C ( n i , 2 ) 2^{C(n-i,2)} 放到一起,再两遍同时除以 n ! n! ,就可以写出两个EGF F ( x ) = f [ n ] i ! x i , G ( x ) = 2 C ( i , 2 ) i ! x i F(x)=\sum \frac{f[n]}{i!}x^i,G(x)=\sum \frac{2^{C(i,2)}}{i!}x^i
这样我们接着处理刚才的式子:
2 C ( n , 2 ) = f [ n ] + i = 1 n 1 f [ i ] n ! i ! ( n i ) ! 2 C ( n i , 2 ) 2^{C(n,2)}=f[n]+\sum_{i=1}^{n-1}f[i]*\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
2 C ( n , 2 ) = i = 1 n f [ i ] n ! i ! ( n i ) ! 2 C ( n i , 2 ) 2^{C(n,2)}=\sum_{i=1}^{n}f[i]\frac{n!}{i!*(n-i)!}*2^{C(n-i,2)}
G ( x ) = F ( x ) G ( x ) + 1 , + 1 i = 0 G(x)=F(x)G(x)+1,此处的+1是因为i=0的时候不满足递推式,所以要加一个常数调整一下
F ( x ) = 1 1 G ( x ) F(x)=1-\frac{1}{G(x)}
多项式求逆求出F(x),就可以解决问题,记得处理好爆int的问题,实在不行就开longlong

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int maxn=1e6+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,fac[maxn],inv[maxn];
inline int ksm(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%mod;
		a=1ll*a*a%mod;b>>=1;
	}
	return ans;
}
int g[maxn],r[maxn];
inline int am(int x){
	if(x>=mod)return x-mod;
	return x;
}
inline void fft(int a[],int lim,int f){
	for(int i=1;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=1;i<lim;i<<=1){
		int wn=ksm(3,(mod-1)/(i<<1));
		if(f==-1)wn=ksm(wn,mod-2);
		for(int j=0;j<lim;j+=(i<<1)){
			int wt=1;
			for(int k=0;k<i;k++,wt=1ll*wt*wn%mod){
				int x=a[j+k],y=1ll*a[j+k+i]*wt%mod;
				a[j+k]=am(x+y);a[j+k+i]=am(x-y+mod);
			}
		}
	}
	if(f==-1){
		int inv=ksm(lim,mod-2);
		for(int i=0;i<lim;i++)a[i]=1ll*a[i]*inv%mod;
	}
}
int lim,l,c[maxn];
int f[maxn];
void getinv(int a[],int b[],int n){
	if(n==1){
		b[0]=ksm(a[0],mod-2);return ;
	}
	getinv(a,b,(n+1)>>1);
	lim=1,l=0;
	while(lim<=(n+n))lim<<=1,l++;
	for(int i=1;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	for(int i=0;i<n;i++)c[i]=a[i];
	for(int i=n;i<lim;i++)c[i]=0;
	fft(c,lim,1);fft(b,lim,1);
	for(int i=0;i<lim;i++)b[i]=1ll*am(2-1ll*c[i]*b[i]%mod+mod)*b[i]%mod;
	fft(b,lim,-1);
	for(int i=n;i<lim;i++)b[i]=0;
}
signed main(){
	n=read();
	fac[0]=inv[0]=1;
	for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
	inv[n]=ksm(fac[n],mod-2);
	for(int i=n-1;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=0;i<=n;i++)g[i]=ksm(2,(i*(i-1)/2)%(mod-1));
	for(int i=0;i<=n;i++){
		g[i]=1ll*g[i]*inv[i]%mod;
	}
	getinv(g,f,n+1);
	for(int i=0;i<=n;i++){
		f[i]=am(mod-f[i]);
	}
	f[0]=am(f[0]+1);
	for(int i=0;i<=n;i++)f[i]=1ll*f[i]*fac[i]%mod;
	if(n>=1)puts("1");
	if(n>=2)puts("-1");
	for(int i=3;i<=n;i++)
	printf("%d\n",1ll*fac[i-1]*ksm(2,1ll*i*(i-3)/2%(mod-1))%mod*ksm(f[i],mod-2)%mod);
	return 0;
}
发布了95 篇原创文章 · 获赞 9 · 访问量 3182

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/104503779
今日推荐