玩游戏,洛谷P4705,NTT+生成函数+可怕的公式推导+可怕的代码

正题

      这个游戏整整玩了我三天。

      题意就是要你求ans(k)=\sum_{i=1}^n\sum_{j=1}^m\frac{(a_i+b_j)^k}{nm}。还要你求ans(1)~ans(t)。那我们暂且先不理会nm这玩意儿。

      利用二项式定理,化简一下可以得到:

      ans(k)=\sum_{i=1}^n\sum_{j=1}^m(a_i+b_j)^k \\=\sum_{i=1}^n\sum_{j=1}^m\sum_{z=0}^{k}C_k^z a_i^z*b_j^{k-z} \\=\sum_{z=0}^kC_k^z\sum_{i=1}^na_i^z\sum_{j=1}^mb_j^{k-z} \\=\sum_{z=0}^k\frac{k!}{z!(k-z)!}\sum_{i=1}^na_i^z\sum_{j=1}^mb_j^{k-z} \\=k!\sum_{z=0}^k\frac{\sum_{i=1}^na_i^z}{z!}*\frac{\sum_{j=1}^mb_j^{k-z}}{(k-z)!}

      看到了喜闻乐见的卷积形式,但是我们难以求出可用于卷积的两个数组A(x)=\sum_{i=1}^na_i^x,B(x)=\sum_{i=1}^nb_J^x

      这个其实可以用生成函数来解决,在我的博客中就以这个模型来介绍生成函数,大家可以看看。

      所以我们最后再用这两个函数做一遍卷积,乘上k!后除以nm输出即可。

#include
#include
#include
#include
using namespace std;

const int maxm=1e5*6+10;
int n,m,t;
long long A[maxm],B[maxm];
long long f[maxm],g[maxm],p[maxm],q[maxm];
long long inv[maxm],fac[maxm];
int limit,l,where[maxm];
const long long mod=998244353;

long long ksm(long long x,long long t){
    long long tot=1;
    while(t){
        if(t&1) (tot*=x)%=mod;
        (x*=x)%=mod;
        t/=2;
    }
    return tot;
}

void ntt(long long *now,int idft){
    for(int i=0;i>1]>>1)|((i&1)<<(l-1)));
    for(int i=0;i<=b-a;i++) f[i]=now[a+i];
    for(int i=0;i<=d-c;i++) g[i]=now[c+i];
    ntt(f,1);ntt(g,1);
    for(int i=0;i>1]>>1)|((i&1)<<(l-1))),q[i]=0;
    for(int i=0;i>1]>>1)|((i&1)<<(l-1)));
    ntt(a,1);ntt(b,1);
    for(int i=0;i=0;i--) inv[i]=(inv[i+1]*(i+1))%mod;
    get_inv(f,A,op+1);get_inv(g,B,op+1);
    for(int i=0;i<=n;i++) A[i]=A[i+1]*(i+1)%mod;
    for(int i=0;i<=m;i++) B[i]=B[i+1]*(i+1)%mod;
    mul(A,f,n,op+1);mul(B,g,m,op+1);
    for(int i=op;i>=1;i--) A[i]=(mod-A[i-1])%mod*inv[i]%mod;A[0]=n;
    for(int i=op;i>=1;i--) B[i]=(mod-B[i-1])%mod*inv[i]%mod;B[0]=m;
    mul(A,B,op+1,op+1);
    long long temp=ksm((long long)n*m%mod,mod-2);
    for(int i=1;i<=t;i++) printf("%lld\n",A[i]*fac[i]%mod*temp%mod);
}

 

你可能感兴趣的:(玩游戏,洛谷P4705,NTT+生成函数+可怕的公式推导+可怕的代码)