其他分享
首页 > 其他分享> > AOJ 4620 -- 饥饿的熊猫

AOJ 4620 -- 饥饿的熊猫

作者:互联网

题链

分析

结论:由n个点组成的大小分别为\(a_1,a_2,\cdots,a_k\)的联通块,再加入\(k\)条边形成一棵树的方案数为\((\prod a_i)\times n^k-2\)

所以不妨考虑一个节的生成函数:

\[G(x)=\sum_{k\in B}\frac{k}{k!}x^k \]

答案为:

\[\sum_{k\in A}\frac{n^{k-2}}{k!}n![x^n]G(x)^k \]

设:

\[F(x)=\sum_{x\in A}\frac{n^{k-2}}{k!}x^k \]

即求

\[n![x^n]F(G(x)) \]

多项式复合即可

#include<bits/stdc++.h>
#define ll long long
const int p=998244353,g=3;
using namespace std;

const int N=2e4+5;
int n,S,a[N],len,b[N],b1[80][N],b2[80][N],R[N],gi,d[N],ans[N];
int ksm(ll a,int b) {
	ll ret=1;
	while(b) {
		if(b&1) ret=ret*a%p;
		a=a*a%p,b>>=1;
	}
	return ret;
}
int mo(int x) {
	return x>=p?x-p:x;
}
void ntt(int *a,int len,int op) {
	int L=0;
	for(int i=1;i<len;i<<=1) L++;
	for(int i=0;i<len;i++) {
		R[i]=R[i>>1]>>1|((i&1)<<L-1);
		if(i>R[i]) swap(a[i],a[R[i]]);
	}
	for(int i=1;i<len;i<<=1) {
		int Wn=ksm(op==1?g:gi,(p-1)/(i<<1));
		for(int j=0;j<len;j+=(i<<1)) {
			ll w=1;
			for(int k=j;k<j+i;k++) {
				int t=w*a[k+i]%p;
				a[k+i]=mo(a[k]-t+p);
				a[k]=mo(a[k]+t);
				w=w*Wn%p;	
			}
		}
	}
	if(op==-1) {
		int t=ksm(len,p-2);
		for(int i=0;i<len;i++) a[i]=(ll)a[i]*t%p;
	}
}
void init() {
	for(int j=0;j<len;j++) d[j]=b[j];
	fill(d+len,d+(len<<1),0);
	ntt(d,len<<1,1);
	b2[0][0]=1; 
	for(int i=1;i<=S;i++) {
		for(int j=0;j<len;j++) {
			b2[i][j]=b2[i-1][j];
		}
		ntt(b2[i],len<<1,1);
		for(int j=0;j<(len<<1);j++) b2[i][j]=(ll)b2[i][j]*d[j]%p;
		ntt(b2[i],len<<1,-1);
		fill(b2[i]+len,b2[i]+(len<<1),0);
	}
	for(int j=0;j<len;j++) {
		d[j]=b2[S][j];
	}
	fill(d+len,d+(len<<1),0);
	b1[0][0]=1;
	ntt(d,len<<1,1);
	for(int i=1;i<=n/S;i++) {
		for(int j=0;j<len;j++) {
			b1[i][j]=b1[i-1][j];
		}
		ntt(b1[i],len<<1,1);
		for(int j=0;j<(len<<1);j++) b1[i][j]=(ll)b1[i][j]*d[j]%p;
		ntt(b1[i],len<<1,-1);
		fill(b1[i]+len,b1[i]+(len<<1),0);
	}
}
int inv[N];
int main() {
	gi=ksm(g,p-2); 
	scanf("%d",&n); n++;
	inv[0]=inv[1]=1;
	for(int i=2;i<n;i++) inv[i]=(ll)(p-p/i)*inv[p%i]%p;
	for(int i=2;i<n;i++) {
		inv[i]=(ll)inv[i]*inv[i-1]%p;
	}
	int K; scanf("%d",&K);
	for(int i=1;i<=K;i++) {
		int k; scanf("%d",&k);
		a[k]=(ll)ksm(n-1,p-1+k-2)*inv[k]%p;
	}
	scanf("%d",&K);
	for(int i=1;i<=K;i++) {
		int k; scanf("%d",&k);
		b[k]=(ll)k*inv[k]%p;
	}
	for(len=1;len<n;len<<=1);
	S=sqrt(n);
	init();
	for(int i=0;i<=n/S;i++) {
		memset(d,0,sizeof(d));
		for(int j=0;j<min(S,n-i*S);j++) {
			for(int k=0;k<n;k++) {
				d[k]=((ll)d[k]+(ll)b2[j][k]*a[i*S+j])%p;
			}
		}
		ntt(d,len<<1,1); ntt(b1[i],len<<1,1);
		for(int j=0;j<(len<<1);j++) d[j]=(ll)d[j]*b1[i][j]%p;
		ntt(d,len<<1,-1);
		for(int j=0;j<n;j++) {
			ans[j]=mo(ans[j]+d[j]);
		}
	}
	for(int i=2;i<n;i++) ans[n-1]=(ll)ans[n-1]*i%p;
	printf("%d\n",ans[n-1]);
	return 0;
}

标签:frac,--,sum,AOJ,ret,4620,int,return,ll
来源: https://www.cnblogs.com/wsfwsf/p/14824803.html