• 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;
    }
    
  • 相关阅读:
    清空map
    读取图片的DLL
    利用SysMailer发送邮件
    使用维度显示
    获取用户所属仓库与库位 Owner 所属仓位
    使用电子邮件模板
    使用SQL获取TableID
    导入数据到excel
    ax附件存取研究
    两步转移 过账
  • 原文地址:https://www.cnblogs.com/WinterSpell/p/13374425.html
Copyright © 2020-2023  润新知