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