• [题解] LuoguP4705玩游戏


    https://www.luogu.com.cn/problem/P4705

    多项式毒瘤题...

    由于是随机选的,所以每次选到(a_i)(b_j)的概率就是(frac{1}{nm}),那么期望就是

    [Ans_k=frac{1}{nm}sumlimits_{i=1}^nsumlimits_{j=1}^m (a_i+b_j)^k ]

    先不管(frac{1}{nm}),我们要求(sum_{i=1}^nsum_{j=1}^m(a_i+b_j)^k),大力二项式定理

    [egin{aligned}Ans_k imes nm &=sumlimits_{i=1}^nsumlimits_{j=1}^m sumlimits_{t=0}^k inom{k}{t}a_i^{t}b_j^{k-t}\&=sumlimits_{t=0}^kfrac{k!}{t!(k-t)!}sumlimits_{i=1}^na_i^{t}sumlimits_{j=1}^ma_j^{k-t}\&=k!sumlimits_{t=0}^k left(sumlimits_{i=1}^nfrac{a_i^t}{t!} ight)left(sumlimits_{j=1}^mfrac{b_j^{k-t}}{(k-t)!} ight)end{aligned} ]

    (A_k=frac{sum_{i=1}^na_i^k}{k!})(B_k=frac{sum_{i=1}^m b_i^k}{k!}),那么

    [Ans_k imes nm=k!sumlimits_{i=0}^k A_iB_{k-i} ]

    如果能快速求出(A,B),卷积就好了,考虑求这个数列

    (f_k=sumlimits_{i=1}^n a_i^k)

    如果能求出(f)的话,用(A_i=frac{f_i}{i!})(A,B)就好了。

    构造其生成函数(F(x)=sumlimits_{i=0}^{infty}f_ix^i=sumlimits_{i=0}^{infty}x^isumlimits_{j=1}^n a_j^i=sumlimits_{j=1}^nsumlimits_{i=0}^{infty}a_j^ix^i=sumlimits_{j=1}^n frac{1}{1-a_jx})

    然后就推不下去了2333

    我们要求的是(sum_{i=1}^n frac{1}{1-a_ix})

    注意到((ln u)'=frac{u'}{u}),那么(ln (1-a_ix)'=frac{-a_i}{1-a_ix}),惊讶的发现

    [frac{1}{1-a_ix}=1-frac{-a_ix}{1-a_ix}=1-xln(1-a_ix)' ]

    太神奇辣~~

    所以

    [F(x)=sumlimits_{i=1}^n frac{1}{1-a_ix}=sumlimits_{i=1}^n 1-xln(1-a_ix)'=n-xsumlimits_{i=1}^n ln(1-a_ix)' ]

    然后把求导拎到外面,在把求和移到(ln)里面变成乘积,所以

    [F(x)=n-xleft(lnprodlimits_{i=1}^n(1-a_ix) ight)' ]

    里面乘法分治算一下就好了。

    (F(x))求出来了过后就可以把(A)求出来,类似的(B)也这样做就好了。

    最后别忘除以nm...

    但是说得简单这代码写的是真的爽......

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for (int i=(a);i<(b);++i)
    #define per(i,a,b) for (int i=(a)-1;i>=(b);--i)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    #define SZ(x) ((int)(x).size())
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    
    const int N=3e5+10,P=998244353,gn=3,ign=332748118;
    
    inline int add(int x,int y) {return (x+=y)>=P?x-P:x;}
    inline int sub(int x,int y) {return (x-=y)<0?x+P:x;}
    inline int fpow(int x,int y) {
        int ret=1; for (;y;y>>=1,x=1ll*x*x%P) 
            if (y&1) ret=1ll*ret*x%P; 
        return ret;
    }
    
    namespace Poly {
        int rev[N];
        void init(int n) {rep(i,0,n) rev[i]=rev[i>>1]>>1|((i&1)?n>>1:0);}
    
        void ntt(int *f,int n,int flg) {
            rep(i,0,n) if (rev[i]<i) swap(f[i],f[rev[i]]);
            for (int len=2,k=1;len<=n;len<<=1,k<<=1) {
                int wn=fpow(flg==1?gn:ign,(P-1)/len);
                for (int i=0;i<n;i+=len)
                    for (int j=i,w=1;j<i+k;j++,w=1ll*w*wn%P) {
                        int tmp=1ll*f[j+k]*w%P;
                        f[j+k]=sub(f[j],tmp),f[j]=add(f[j],tmp);
                    }
            }
            if (flg==-1) {
                int inv=fpow(n,P-2);
                rep(i,0,n) f[i]=1ll*f[i]*inv%P;
            }
        }
    
        void dao(int *f,int n,int *g) {
            static int F[N]; rep(i,0,n) F[i]=f[i];
            rep(i,1,n) g[i-1]=1ll*F[i]*i%P;g[n]=0;
        }
        void jifen(int *f,int n,int *g) {
            static int F[N]; rep(i,0,n) F[i]=f[i];
            rep(i,0,n) g[i+1]=1ll*F[i]*fpow(i+1,P-2)%P;g[0]=0;
        }
    
        void getinv(int *f,int n,int *G) {
            if (n==1) {G[0]=fpow(f[0],P-2);return;}
            getinv(f,(n+1)>>1,G);
            static int F[N]; int limit=1;
            while(limit<=2*(n-1)) limit<<=1; init(limit);
            rep(i,0,limit) F[i]=i>=n?0:f[i],G[i]=i>=n?0:G[i];
            ntt(F,limit,1),ntt(G,limit,1);
            rep(i,0,limit) G[i]=1ll*G[i]*sub(2,1ll*F[i]*G[i]%P)%P;
            ntt(G,limit,-1);
            rep(i,n,limit) G[i]=0;
        }
    
        void getln(int *f,int n,int *G) {
            static int derv[N],inv[N];
            getinv(f,n,inv),dao(f,n,derv);
            int limit=1; while(limit<=2*(n-1)) limit<<=1; init(limit);
            rep(i,n,limit) derv[i]=inv[i]=0;
            ntt(derv,limit,1),ntt(inv,limit,1);
            rep(i,0,limit) G[i]=1ll*derv[i]*inv[i]%P;
            ntt(G,limit,-1);
            jifen(G,n,G);
            rep(i,n,limit) G[i]=0;
        }
    }
    using Poly::ntt;
    using Poly::getinv;
    using Poly::getln;
    using Poly::dao;
    
    int tn,ifac[N],fac[N],inv[N];
    
    void init(int n) {
        ifac[0]=ifac[1]=fac[0]=fac[1]=inv[1]=1;
        rep(i,2,n+1) {
            inv[i]=1ll*inv[P%i]*(P-P/i)%P;
            ifac[i]=1ll*ifac[i-1]*inv[i]%P;
            fac[i]=1ll*fac[i-1]*i%P;
        }
    }
    
    void fff(int *a,int l,int r,int *F) {
        if (l==r) {F[0]=1,F[1]=(P-a[l])%P;return;}
        int mid=(l+r)>>1;
        int Fl[N],Fr[N];   // 这里分治乘就直接把数组开在函数里了...不知道有没有更妙的做法qwq
        fff(a,l,mid,Fl),fff(a,mid+1,r,Fr);
        int limit=1; while(limit<=r-l+1) limit<<=1; Poly::init(limit);
        rep(i,mid-l+2,limit) Fl[i]=0;
        rep(i,r-mid+1,limit) Fr[i]=0;
        ntt(Fl,limit,1),ntt(Fr,limit,1);
        rep(i,0,limit) F[i]=1ll*Fl[i]*Fr[i]%P;    
        ntt(F,limit,-1);
        rep(i,r-l+2,limit) F[i]=0;
    }
    
    void getF(int *a,int n,int *F) {
        fff(a,1,n,F); static int G[N];
        getln(F,tn+1,G);
        dao(G,tn+1,F);
        per(i,tn+1,1) F[i]=P-F[i-1];
        F[0]=n;
        rep(i,0,tn+1) F[i]=1ll*F[i]*ifac[i]%P; 
    }
    
    int n,m,K,a[N],b[N],A[N],B[N];
    int main() {
    #ifdef LOCAL
        freopen("a.in","r",stdin);
    #endif
        scanf("%d%d",&n,&m);
        rep(i,1,n+1) scanf("%d",&a[i]);
        rep(i,1,m+1) scanf("%d",&b[i]);
        scanf("%d",&K); init(tn=max(max(n,m),K));
        getF(a,n,A),getF(b,m,B);
        int limit=1; while(limit<=2*tn) limit<<=1; Poly::init(limit);
        ntt(A,limit,1),ntt(B,limit,1);
        rep(i,0,limit) A[i]=1ll*A[i]*B[i]%P;
        ntt(A,limit,-1); int iv=fpow(1ll*n*m%P,P-2);
        rep(i,1,K+1) printf("%d
    ",1ll*iv*fac[i]%P*A[i]%P);
        return 0;
    }
    
  • 相关阅读:
    docker 安装mysql5.7 加my.cnf
    docker安装redis 配置文件
    私库nexus 配置
    mysql 多个字段建立唯一索引
    scm 一些记录
    tomcat 线程数、NIO配置、内存配置
    为什么简单的一个select查询都要加上事务控制
    powerdeginer report layout
    powerdesigner-连接mysql
    [转载]如何让自己变得有趣
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12383329.html
Copyright © 2020-2023  润新知