P5641 【CSGRound2】开拓者的卓识
像我这种菜鸡只能从组合意义考虑了,还要感谢 \(\color{black}{\texttt{c}}\color{red}{\texttt{yn2006}}\) 的指导。
题目的公式比较鬼畜,考虑从 \(a_i\) 对 \(sum_{k,1,r}\) 的贡献入手考虑。
相当于我们要找有多少种“套娃”一样的区间包括 \(i\) 并且最大的那个是 \([1,r]\)。
即 \(1\le l_{k}\le l_{k}\le\cdots i\cdots\le r_{k-2}\le r_{k-1}\le r\) 的不同 \(\{[l_1,r_1],[l_2,r_2],\cdots,[l_{k},r_{k}]\}\) 有几个
显然左右端点是独立的。
所以贡献为 \(a_i\times\binom{i+k-2}{k-1}\binom{r-i+k-1}{k-1}\)
意思就是每次左端点可以选择留在原地或者往左走,最多往左走 \(i-1\) 步。直接插板即可。
最好先观察一下,不要直接暴力拆阶乘。
发现下指标全是 \(k-1\) ,那么设 \(p_i=\binom{k-1+i}{k-1}\),这个可以递推,考虑 \(\binom{n-1}{m}\to\binom{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;
}
路漫漫其修远兮,吾将上下而求索