P5641. 【CSGRound2】开拓者的卓识
作者:互联网
\(\text{Solution}\)
推柿子比较套路,考虑每一个\(a_i\)对\(sum_{k,1,j}\)的贡献即可。
看看\(sum\)是如何转移的
其中\(1 \le l_k \le l_{k - 1} \le ... \le i \le ... \le r_k \le j\)
那我们只需考虑\(l,r\)组合的方案数即可,用插板法计算为
所以
\[sum_{k,1,j} = \sum_{i = 1}^{j}a_i\binom{i + k - 2}{k - 1}\binom{j - i + k - 1}{k - 1} \]设
\[A_i = a_{i}\binom{i + k - 2}{k - 1} = \frac{a_ik^{\overline{i - 1}}}{(i - 1)!},B_i = \binom{i + k - 1}{k - 1} = \frac{k^{\overline{i}}}{i!} \]这样可以快速计算\(A_i,B_i\)。
\[sum_{k,1,j} = \sum_{i + (j - i) = j}A_iB_{j - i} \]这样就是卷积了。
\(\text{Code}\)
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 1e5 + 5,P = 998244353;
int n,rev[N * 3]; LL k,a[N],b[N],f[N * 3],g[N * 3];
LL fpow(LL x,LL y)
{
LL res = 1;
for (; x; x >>= 1,y = y * y % P)
if (x & 1) res = res * y % P;
return res;
}
void NTT(LL *f,int len,int fl)
{
if (len == 1) return;
for (int i = 0; i < len; i++)
if (i < rev[i]) swap(f[i],f[rev[i]]);
for (int l = 1; l < len; l <<= 1)
{
LL I = fpow((P - 1) / (l << 1),3);
if (fl == -1) I = fpow(P - 2,I);
for (int i = 0; i < len; i += (l << 1))
{
LL W = 1;
for (int j = 0; j < l; j++,W = W * I % P)
{
LL x = f[i + j],y = W * f[i + j + l] % P;
f[i + j] = (x + y) % P,f[i + j + l] = (x - y + P) % P;
}
}
}
}
int main()
{
scanf("%d%lld",&n,&k);
for (int i = 1; i <= n; i++) scanf("%lld",&a[i]);
b[0] = 1;
for (int i = 1; i <= n; i++) b[i] = b[i - 1] * (k + i - 1) % P * fpow(P - 2,i) % P;
for (int i = 1; i <= n; i++) f[i] = a[i] * b[i - 1] % P;
for (int i = 1; i <= n; i++) g[i] = b[i]; g[0] = 1;
int len = 1,bit = 0;
while (len <= n << 1) len <<= 1,bit++;
for (int i = 1; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
NTT(f,len,1),NTT(g,len,1);
for (int i = 0; i < len; i++) f[i] = f[i] * g[i] % P;
NTT(f,len,-1); LL inv = fpow(P - 2,len);
for (int i = 1; i <= n; i++) printf("%lld ",inv * f[i] % P);
}
标签:le,res,int,P5641,CSGRound2,卓识,sum,binom,LL 来源: https://www.cnblogs.com/nibabadeboke/p/16478383.html