hdu5279 YJC plays Minecraft

(n)个点的有标号树总共有(n^{n-2})
(f[i])表示(i)个点有标号森林个数
枚举一号点所在树大小 有

[f[n]=sum_{i=1}^ninom{n-1}{i-1}i^{i-2}f[n-i] ]

可以通过分治fft解决
其实也完全可以用EGF的语言叙述 比如如果令(T(x))(i)个点有标号树个数的EGF 那么(F(x)=exp T(x)) 只不过我过于不熟练
考虑将每个部分的(f[a[i]])乘起来 环上的边自由选择即乘上(2^n)
但这样最终答案多算了一个不合法的情况:所有环上的边都被选择且每个块的一号点与(a[i])号点连通
(g[i])表示(i)个点有标号生成森林且满足一号点与(i)号点连通方案数
还是枚举一号点与(i)号点所在树 有

[g[n]=sum_{i=2}^{n}inom{n-2}{i-2}i^{i-2}f[n-i] ]

[ans=2^n imesprod_i f[a[i]]-prod_i g[a[i]] ]

又一次为了偷懒写成(O(nlog^2 n))

#include<bits/stdc++.h>
using namespace std;
#define fp(i,l,r) for(register int (i)=(l);i<=(r);++(i))
#define fd(i,l,r) for(register int (i)=(l);i>=(r);--(i))
#define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
#define mem(a) memset((a),0,sizeof (a))
#define O(x) cerr<<#x<<':'<<x<<endl
#define int long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
void wr(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>=10)wr(x/10);
    putchar('0'+x%10);
}
const int MAXN=280000,mod=998244353;
int t1[MAXN],t2[MAXN],tr[MAXN],lim,GG[MAXN],gg[MAXN];
int F[MAXN],G[MAXN],tot,fac[MAXN],ifac[MAXN],pw[MAXN];
inline void tmod(int &x){x%=mod;}
inline void rmod(int &x){x+=x>>31&mod;} 
inline int qpow(int a,int b){
    int res=1;
    for(;b;b>>=1,tmod(a*=a))
    if(b&1)tmod(res*=a);
    return res;
}
inline int ginv(int x){return qpow(x,mod-2);}
inline void ntt(int a[],bool flag){
    fp(i,0,lim-1)if(i<tr[i])swap(a[i],a[tr[i]]);
    for(int p=2;p<=lim;p<<=1){
        const int len=p/2,muli=(1<<18)/p;
        fp(j,0,len-1)gg[j]=GG[j*muli];
        for(int i=0;i<lim;i+=p)
        fp(j,i,i+len-1){
            const int L=a[j],R=a[j+len]*gg[j-i]%mod;
            rmod(a[j]+=R-mod);rmod(a[j+len]=L-R);
        }
    }
    if(!flag)return;const int I=ginv(lim);reverse(a+1,a+lim);
    fp(i,0,lim-1)tmod(a[i]*=I);
}
inline void getlim(int n){
    for(lim=1;lim<=n;lim<<=1);
    fp(i,0,lim-1)tr[i]=(tr[i>>1]>>1)|(i&1?lim>>1:0);
}
void dac(int l,int r){
    if(r-l==1){F[l]=(l?F[l]*fac[l-1]%mod:1);return;}
    int mid=l+r>>1;dac(l,mid);
    lim=r-l;
    fp(i,0,lim-1)tr[i]=(tr[i>>1]>>1)|(i&1?lim>>1:0);
    t1[0]=0;fp(i,1,r-l-1)tmod(t1[i]=pw[i]*ifac[i-1]);
    fp(i,0,mid-l-1)tmod(t2[i]=ifac[i+l]*F[i+l]);fp(i,mid-l,lim-1)t2[i]=0;
    ntt(t1,0);ntt(t2,0);
    fp(i,0,lim-1)tmod(t1[i]*=t2[i]);
    ntt(t1,1);
    fp(i,mid,r-1)rmod(F[i]+=t1[i-l]-mod);dac(mid,r);
}
inline void prework(int n){
    fac[0]=pw[1]=1;
    fp(i,1,n+2)tmod(fac[i]=fac[i-1]*i);ifac[n+2]=ginv(fac[n+2]);
    fd(i,n+1,0)tmod(ifac[i]=ifac[i+1]*(i+1));
    fp(i,2,n+2)pw[i]=qpow(i,i-2);
    for(tot=1;tot<=n;tot<<=1);dac(0,tot);
    t1[0]=t1[1]=0;getlim(2*n);
    fp(i,2,n)tmod(t1[i]=ifac[i-2]*pw[i]);fp(i,n+1,lim-1)t1[i]=0;
    fp(i,0,n)tmod(t2[i]=F[i]*ifac[i]);fp(i,n+1,lim-1)t2[i]=0;
    ntt(t1,0);ntt(t2,0);
    fp(i,0,lim-1)tmod(G[i]=t1[i]*t2[i]);
    ntt(G,1);
    fp(i,2,n)tmod(G[i]*=fac[i-2]);
    G[1]=1;
}
inline void solve(){
    int n=read(),res1=qpow(2,n),res2=1;
    fp(i,1,n){
        int x=read();tmod(res1*=F[x]);tmod(res2*=G[x]);
    }
    printf("%lld
",(res1-res2+mod)%mod);
}
main(){
    GG[0]=1;GG[1]=qpow(3,(mod-1)/(1<<18));
    fp(i,2,MAXN-1)tmod(GG[i]=GG[i-1]*GG[1]);prework(100000);
    int tt=read();
    while(tt--)solve();
    return 0;
}
原文地址:https://www.cnblogs.com/misaka10047/p/13374425.html