Description:
求数列
a
a
的次前缀和。
Solution:
感觉还不错。经过思考发现构造一个全
1
1
卷积,每次和卷上后相当于做一次前缀和。由于
k
k
比较大,我们可以写一个多项式快速幂,但是复杂度过高。
事实上全数列的
k
k
次卷积,于是我们算出这个数列,和
a
a
<script type="math/tex" id="MathJax-Element-90">a</script>卷起来就是答案了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5, P = 998244353;
int n, m, len;
ll k;
ll a[N], b[N];
ll power(ll x, ll t) {
ll ret = 1;
for(; t; t >>= 1, x = x * x % P) {
if(t & 1) {
ret = ret * x % P;
}
}
return ret;
}
void ntt(ll *a, int f) {
for(int i = 0; i < n; ++i) {
int t = 0;
for(int j = 0; j < len; ++j) {
if(i & (1 << j)) {
t |= 1 << (len - j - 1);
}
}
if(i < t) {
swap(a[i], a[t]);
}
}
for(int l = 2; l <= n; l <<= 1) {
int m = l >> 1;
ll w = power(3, f == 1 ? (P - 1) / l : (P - 1) - (P - 1) / l);
for(int i = 0; i < n; i += l) {
ll t = 1;
for(int k = 0; k < m; ++k, t = t * w % P) {
ll x = a[i + k], y = t * a[i + m + k] % P;
a[i + k] = (x + y) % P;
a[i + m + k] = (x - y + P) % P;
}
}
}
if(f == -1) {
ll inv = power(n, P - 2);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * inv % P;
}
}
}
void sqr(ll *a) {
ntt(a, 1);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * a[i] % P;
}
ntt(a, -1);
for(int i = m; i < n + m; ++i) {
a[i] = 0;
}
}
int main() {
scanf("%d%lld", &m, &k);
for(n = 1; n <= 2 * m; n <<= 1) {
++len;
}
for(int i = 0; i < m; ++i) {
scanf("%lld", &a[i]);
}
b[0] = 1;
for(int i = 1; i < m; ++i) {
b[i] = b[i - 1] * ((k + i - 1) % P) % P * power(i, P - 2) % P;
}
ntt(a, 1);
ntt(b, 1);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * b[i] % P;
}
ntt(a, -1);
for(int i = 0; i < m; ++i) {
printf("%lld\n", a[i]);
}
return 0;
}