题目链接:
题意:
给长度为的序列
,求其
次前缀和,前缀和对998244353取模。
前置知识:
参考自右链接,写的超棒:数据结构专题班:1 前缀和与差分_wavecho的博客-CSDN博客
如果序列做前缀和取的模数大于序列的长度,前缀和序列会以 模数长度 的循环节循环出现。
题目中的模数大于序列长度,可以对负数的k (差分) 取模后转化为前缀和。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
const ll mod = 998244353;
namespace NTT//取模ntt模板
{
const long long g = 3;
const long long p = 998244353;
long long wn[35];
long long pow2(long long a, long long b)
{
long long res = 1;
while (b)
{
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
void getwn()
{
for (int i = 0; i < 25; i++) wn[i] = pow2(g, (p - 1) / (1LL << i));
}
void ntt(long long *a, int len, int f)
{
long long i, j = 0, t, k, w, id;
for (i = 1; i < len - 1; i++)
{
for (t = len; j ^= t >>= 1, ~j & t;);
if (i < j) swap(a[i], a[j]);
}
for (i = 1, id = 1; i < len; i <<= 1, id++)
{
t = i << 1;
for (j = 0; j < len; j += t)
{
for (k = 0, w = 1; k < i; k++, w = w * wn[id] % p)
{
long long x = a[j + k], y = w * a[j + k + i] % p;
a[j + k] = (x + y) % p;
a[j + k + i] = (x - y + p) % p;
}
}
}
if (f)
{
for (i = 1, j = len - 1; i < j; i++, j--) swap(a[i], a[j]);
long long inv = pow2(len, p - 2);
for (i = 0; i < len; i++) a[i] = a[i] * inv % p;
}
}
void mul(long long *a, long long *b, int l1, int l2)
{
getwn();
int len, i;
for (len = 1; len <= l1 + l2; len <<= 1);
for (i = l1 + 1; i <= len; i++) a[i] = 0;
for (i = l2 + 1; i <= len; i++) b[i] = 0;
ntt(a, len, 0); ntt(b, len, 0);
for (i = 0; i < len; i++) a[i] = a[i] * b[i] % p;
ntt(a, len, 1);
}
};
ll n,k;
ll a[maxn];
ll inv[maxn];
ll ki[maxn];
//线性时间求逆元
void init(long long n)
{
inv[0] = inv[1] = 1;
for (long long i = 2; i <= n; i++)
{
inv[i] = ((mod - mod / i) * inv[mod % i]) % mod;
}
return;
}
void get_ki(long long k, int len)
{
k = (k % mod + mod) % mod;
ki[0] = 1;
for (int i = 1; i < len; ++i)
{
ki[i] = ki[i - 1] * inv[i] % mod * ((k + i - 1) % mod) % mod;
}
}
int main(){
init(100000);
scanf("%lld%lld",&n,&k);
get_ki(k,n);
for(int i = 0;i < n;i++){
scanf("%lld",&a[i]);
}
NTT::mul(a,ki,n,n);
/*
a数组为初始序列
ki为求k次前缀和的系数[1,3,6,10...]
*/
for(int i = 0;i < n;i++)
printf("%lld%c",a[i],i == n - 1?'\n':' ');
return 0;
}