LOJ#6261. 一个人的高三楼 组合+NTT

令 $f(i,j)$ 表示 $j$ 的 $i$ 阶前缀和.  

那么有 $f(i,j)=\sum_{j=1}^{i} f(i-1,j)$,这个可以直接多项式快速幂.  

时间复杂度是 $O(n \log^2 n)$  或 $O(n \log n)$ ,但是常数大而且第二种不好写.    

考虑计算每一个位置 $j \leqslant i$ 对 $i$ 位置的贡献.  

令 $p(i,j,k)$ 表示 $j$ 对 $i$ 的 $k$ 阶前缀和的贡献系数,那么有: 

$p(i,j,k)=\sum_{t=1}^{i} p(t,j,k-1)$.   

组合意义上可以看作将 $j-i$ 分成 $k$ 份的方案数,即 $\binom{j-i+k-1}{k-1}$.     

构建生成函数 $B(x)=\sum_{i=0}^{\infty} \binom{i+k-1}{i} x^i$ 然后和 $A(x)=\sum_{i=0}^{n} a_{i} x^i$ 卷一下即可. 

code: 

#include <cstdio> 
#include <cstring>  
#include <algorithm>  
#define N 400009
#define ll long long 
#define mod 998244353
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;        
ll kth;  
int A[N],B[N],inv[N],n;  
int qpow(int x,int y) { 
    int tmp=1; 
    for(;y;y>>=1,x=(ll)x*x%mod)  
        if(y&1) tmp=(ll)tmp*x%mod;  
    return tmp;  
}  
int get_inv(int x) {  
    return qpow(x,mod-2); 
}   
void NTT(int *a,int len,int op) {  
    for(int i=0,k=0;i<len;++i) {  
        if(i>k) swap(a[i],a[k]); 
        for(int j=len>>1;(k^=j)<j;j>>=1); 
    }
    for(int l=1;l<len;l<<=1) {   
        int w=qpow(3,(mod-1)/(l<<1)),wn,x,y;   
        if(op==-1) w=get_inv(w);   
        for(int i=0;i<len;i+=l<<1) {    
            wn=1; 
            for(int j=0;j<l;++j) {    
                x=a[i+j],y=(ll)a[i+j+l]*wn%mod;    
                a[i+j]=(ll)(x+y)%mod;  
                a[i+j+l]=(ll)(x-y+mod)%mod;    
                wn=(ll)wn*w%mod;  
            }  
        }
    }     
    if(op==-1) {   
        int p=get_inv(len);  
        for(int i=0;i<len;++i) { 
            a[i]=(ll)a[i]*p%mod;  
        }
    }
}     
void init() { 
    inv[1]=1; 
    for(int i=2;i<N;++i) { 
        inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;  
    }     
    inv[0]=1;  
    for(int i=1;i<N;++i) {
        inv[i]=(ll)inv[i-1]*inv[i]%mod;  
    }
    ll mul=1;   
    for(int i=0;i<=n;++i) {   
        B[i]=(ll)mul%mod*inv[i]%mod;   
        mul=mul*1ll*((kth+i)%mod)%mod;    
    }
}   
int main() {  
    // setIO("input"); 
    scanf("%d%lld",&n,&kth);    
    init();  
    for(int i=1;i<=n;++i) scanf("%d",&A[i]);     
    int l=1;  
    for(;l<(2*n+1);l<<=1);  
    NTT(A,l,1),NTT(B,l,1); 
    for(int i=0;i<l;++i) {
        A[i]=(ll)A[i]*B[i]%mod; 
    }
    NTT(A,l,-1); 
    for(int i=1;i<=n;++i) {  
        printf("%d\n",A[i]); 
    }
    return 0; 
}

  

     

posted @ 2020-07-21 11:28  EM-LGH  阅读(139)  评论(0编辑  收藏  举报