1. 程式人生 > 其它 >P5488 差分與字首和 NTT技術解決字首和差分

P5488 差分與字首和 NTT技術解決字首和差分

P5488 差分與字首和 NTT技術解決字首和差分

題意

給出序列\(a\),求出序列\(a\)經過\(k\)次差分或者字首和後的序列

注意\(k\)會很大 模數\(1004535809\)

附NTT可用模數表

分析

對於字首和,只需要把\(F\)乘上\(G = \sum_{i=0}^\infty x^i = \frac{1}{1-x}\)

\(k\)次字首和則只需要乘上\(G^k\)

同理\(k\)次差分只要乘上\((1-x)^k\)

此時可以多項式取\(ln\)\(exp\)

也可以觀察性質

\[(1-x)^k = \sum (-1)^i \tbinom{k}{i}x^i \]

有遞推關係

\[\tbinom{k}{0} =1,\tbinom{k}{i} = \tbinom{k}{i-1} \times \frac{k-i+1}{i} \]

且注意到\(k\)

是可以直接取模的

字首和

根據廣義二項式定理\((1-x)^a = \sum (-1)^i \tbinom{a}{i}x^i\)

其中組合數需改寫\(\tbinom{a}{i} = \frac{a^\underline{i}}{i!}\)

其中\(a^{\underline{i}}\) 為下降冪

\[(1-x)^{-k} = \sum(-1)^i\frac{(-k)^{\underline{i}}}{i!}x^i = \sum(-1)^{2k} \frac{{k+i-1}^{\underline{i}}}{i!}x^i = \sum \tbinom{k+i-1}{i}x^i \]

同樣可以找到遞推關係

\[\tbinom{k-1}{0} = 1,\tbinom{k+i-1}{i} = \tbinom{k+i-2}{i-1} \times \frac{k+i-1}{i} \]

於是\(NTT\)即可

程式碼

注意空間要多開點

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define eps 1e-9
#define db long double
#define equals(a,b) fabs(a-b) < eps
using namespace std;

typedef long long ll;


const int MOD = 1004535809;

inline int rd(){
	int x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = (ll)x * 10 % MOD + ch - '0';
		if(x >= MOD ) x -= MOD;
		ch = getchar();
	}
	return x;
}

const int maxn = 2e5 + 5;


class NTTClass{
public:
    static const int MAXL=21;
    static const int MAXN=1<<MAXL;
    static const int root=3;
    static const int MOD= 1004535809 ;
    int rev[MAXN];
 
    int fast_pow(int a,int b){
        int ans=1;
        while(b){
            if(b&1)ans=1ll*ans*a%MOD;
            a=1ll*a*a%MOD;
            b>>=1;
        }
        return ans;
    }
 
    void transform(int n,int *t,int typ){
        for(int i=0;i<n;i++)
            if(i<rev[i])swap(t[i],t[rev[i]]);
        for(int step=1;step<n;step<<=1){
            int gn=fast_pow(root,(MOD-1)/(step<<1));
            for(int i=0;i<n;i+=(step<<1)){
                int g=1;
                for(int j=0;j<step;j++,g=1ll*g*gn%MOD){
                    int x=t[i+j],y=1ll*g*t[i+j+step]%MOD;
                    t[i+j]=(x+y)%MOD;
                    t[i+j+step]=(x-y+MOD)%MOD;
                }
            }
        }
        if(typ==1)return;
        for(int i=1;i<n/2;i++)swap(t[i],t[n-i]);
        int inv=fast_pow(n,MOD-2);
        for(int i=0;i<n;i++)t[i]=1ll*t[i]*inv%MOD;
    }
 
    void ntt(int p,int *A,int *B,int *C){
        transform(p,A,1);
        transform(p,B,1);
        for(int i=0;i<p;i++)C[i]=1ll*A[i]*B[i]%MOD;
        transform(p,C,-1);
    }
 
    void mul(int *A,int *B,int *C,int n,int m) {
        int p=1,l=0;
        while(p<=n+m)p<<=1,l++;
        //printf("n = %d, m = %d\n",n,m);
        for (int i=n+1;i<p;i++) A[i] = 0;
        for (int i=m+1;i<p;i++) B[i] = 0;
        //for (int i=0;i<p;i++) printf("%d ",A[i]);puts("");
        //for (int i=0;i<p;i++) printf("%d ",B[i]);puts("");
        for(int i=0;i<p;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        ntt(p,A,B,C);
        //puts("C:");for (int i=0;i<p;i++) printf("%d ",C[i]);puts("");
    }
}NTT;


int a[2 * maxn],b[2 * maxn],c[2 * maxn];
int v[2 * maxn];



int main(){
	int n = rd();
	int k = rd();
	int t = rd();
	if(t == 1) {
		a[0] = 1;
		for(int i = 1;i <= n;i++)
			a[i] = (ll)(MOD - a[i - 1]) * ((k - i + 1 + MOD) % MOD) % MOD * NTT.fast_pow(i,MOD - 2) % MOD;  
	}
	else {
		a[0] = 1;
		for(int i = 1;i <= n;i++)
			a[i] = (ll)a[i - 1] * (k + i - 1) % MOD * NTT.fast_pow(i,MOD - 2) % MOD;
	}
	for(int i = 0;i < n;i++)
		b[i] = rd();
	NTT.mul(a,b,c,n,n);
	for(int i = 0;i < n;i++)
		printf("%d ",c[i]);
}