像我这种菜鸡只能从组合意义考虑了,还要感谢 (color{black}{ exttt{c}}color{red}{ exttt{yn2006}}) 的指导。
题目的公式比较鬼畜,考虑从 (a_i) 对 (sum_{k,1,r}) 的贡献入手考虑。
相当于我们要找有多少种“套娃”一样的区间包括 (i) 并且最大的那个是 ([1,r])。
即 (1le l_{k}le l_{k}lecdots icdotsle r_{k-2}le r_{k-1}le r) 的不同 ({[l_1,r_1],[l_2,r_2],cdots,[l_{k},r_{k}]}) 有几个
显然左右端点是独立的。
所以贡献为 (a_i imesinom{i+k-2}{k-1}inom{r-i+k-1}{k-1})
意思就是每次左端点可以选择留在原地或者往左走,最多往左走 (i-1) 步。直接插板即可。
最好先观察一下,不要直接暴力拆阶乘。
发现下指标全是 (k-1) ,那么设 (p_i=inom{k-1+i}{k-1}),这个可以递推,考虑 (inom{n-1}{m} oinom{n}{m}) 的变化即可,即乘上 (dfrac{n}{n-m})
所以
(ans_i=sum_{j=1}^{i}a_j p_{j-1}p_{i-j})
可以卷了。
const int N=100005;
const int M=600005;
const int mod=998244353;
int n,k,a[M],p[M],inv[N],rev[M],lg,lim;
int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*res*n%mod;return res;}
void init(int n){
for (lg = 0, lim = 1; lim < n; ++ lg, lim <<= 1);
for (int i = 0; i < lim; ++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
}
void NTT(int*a,int g,int op=0){
for (int i = 0; i < lim; ++ i) if (i > rev[i]) std::swap(a[i], a[rev[i]]);
for (int i = 1; i < lim; i <<= 1) {
int wn = qpow (g, (mod - 1) / (i << 1));
for (int j = 0; j < lim; j += i << 1) {
int w0 = 1;
for (int k = 0; k < i; ++ k, w0 = 1ll * w0 * wn % mod) {
int X = a[j + k], Y = 1ll * w0 * a[i + j + k] % mod;
a[j + k] = (X + Y) % mod, a[i + j + k] = (X - Y + mod) % mod;
}
}
}
if(!op)return;int ilim = qpow(lim, mod - 2);
for (int i = 0; i < lim; ++ i) a[i] = 1ll * a[i] * ilim % mod;
}
signed main(){
n=read(),k=read();
for(int i=1;i<=n;++i)a[i]=read();
p[0]=1,inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;++i)p[i]=1ll*p[i-1]*(k-1+i)%mod*inv[i]%mod,a[i]=1ll*a[i]*p[i-1]%mod;
init(n<<1),NTT(a,3),NTT(p,3);
for(int i=0;i<lim;++i)a[i]=1ll*a[i]*p[i]%mod;
NTT(a,qpow(3,mod-2),1);
for(int i=1;i<=n;++i)printf("%d ",a[i]);
return 0;
}