p5488 差分与前缀和

(5 mins to read)

题意

快速求一个数列a的k阶差分或者k阶前缀和$n \leq 10^5,k\leq 10^{2333},mod=1004535809$

做法

将数列a看成OGF:$F(x) = \sum \limits_{i=0}^{\infty}a_ix^i$作一次前缀和相当于乘以$\sum \limits_{i=0}^{\infty} x^i =\dfrac{1}{1-x}$作一次差分相当于乘以$(1-x)$利用二项式定理:$\dfrac{1}{(1-x)^k} =(1-x)^{-k} = \sum \limits_{i=0}^{\infty} \dfrac{(-k)^{\underline{i}}}{i!}(-x)^i = \sum \limits_{i=0}^{\infty} \dfrac{(k+i-1)^{\underline{i}}}{i!}x^i$线性递推出前n项的系数,然后和a作一次卷积即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5, mod = 1004535809, gen = 3;
int n, k, t, a[N], b[N], inv[N];
int up, l, rev[N];
void read(int &k)
{
char c = getchar();
while(c>'9'||c<'0') c = getchar();
while(c>='0'&&c<='9') k = (1ll*k*10 + c - 48)%mod, c = getchar();
}
int powmod(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;
}
inline void init(int n)
{
up = 1, l = 0;
while(up<=n) up <<= 1, l++;
for(int i=0; i<up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(l-1));
}
void NTT(int *a, int op)
{
for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i], a[rev[i]]);
for(int i=1; i<up; i<<=1)
{
int gn = powmod(gen, (mod-1)/(i<<1));
if(op==-1) gn = powmod(gn, mod-2);
for(int j=0; j<up; j+=(i<<1))
for(int k=0,g=1; k<i; k++,g=1ll*g*gn%mod)
{
int x = a[j+k], y = 1ll*g*a[j+k+i]%mod;
a[j+k] = (x+y)%mod, a[j+k+i] = (x-y+mod)%mod;
}
}
if(op==-1)
{
int invup = powmod(up, mod-2);
for(int i=0; i<up; i++) a[i] = 1ll*a[i]*invup%mod;
}
}
int main()
{
scanf("%d", &n);
inv[0] = inv[1] = 1;
for(int i=2; i<=n; i++) inv[i] = 1ll*(mod-mod/i)*inv[mod%i]%mod;
read(k);
scanf("%d", &t);
for(int i=0; i<n; i++) scanf("%d", &a[i]);
b[0] = 1;
if(t) for(int i=1; i<=n; i++) b[i] = (-1ll*b[i-1]*(k-i+1)%mod*inv[i]%mod+mod)%mod;
else for(int i=1; i<=n; i++) b[i] = 1ll*b[i-1]*(k+i-1)%mod*inv[i]%mod;
init(2*n-1);
NTT(a, 1); NTT(b, 1);
for(int i=0; i<up; i++) a[i] = 1ll*a[i]*b[i]%mod;
NTT(a, -1);
for(int i=0; i<n; i++) printf("%d%c", a[i], " \n"[i==n-1]);
return 0;
}