P5488 差分與字首和 NTT技術解決字首和差分
阿新 • • 發佈:2021-07-14
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 \]同樣可以找到遞推關係
於是\(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]); }