Description
给定 \(n,w\) 和长度为 \(n\) 的序列 \(c\),求
的值模 \(998244353\) 的结果
\(n\le 10^5,w\le 10^18,\sum c\le 10^5\)
Solution
写出 \(\rm OGF\) 大概可以把答案写成下式并进行一定程度的和式变换
最后一步使用了数列 \(a_n=\binom{n+m}{m}\)(\(m\) 为常数)的 \(\rm OGF\) 为 \((\frac1{1-x})^{m+1}\),证明考虑对常数 \(m\) 归纳,使用了最基础的组合数求一行的和
将 \(\frac 1{1-x}\) 看做自变量,剩下的看成多项式可以分治乘法求出多项式本身,但是别扭的是这个 \(x^p\),不过对于每个 \(p+1\) 都会配凑一个 \(p\),\(n\) 个式子累乘起来那么对于 \((\frac 1{1-x})^m\) 的项必然跟着一个 \(x^{m-n}\),找指数时对着等号最前面的 \([x^k]\) 的 \(k\) 减就行了
分治乘法的叶子处需要快速求第二类斯特林数一行,由于 \(\sum c_i\) 的上界是可以接受的,那么逐个快速求就行了
剩下的工作是统计答案,考虑 \(f_px^{p-n}(\frac 1{1-x})^p\) 对某个 \(x^{r}\) 的贡献系数:现将 \(r\) 减掉 \(p-n\),\([x^{r-(p-n)}]\left(\frac{1}{1-x}\right)^p=\binom{r+n-1}{p-1}\)
直接对着 \(r\in[0,w-(p-n)]\) 求一列和就能得到 \(\binom {w+n}p\),即 \(f_p\) 对答案的贡献
组合数推一下就行了,不要直接算
写题解的初衷是看网上没有题解,所以希望能给有需要的人一些帮助吧
Code
inline poly Mul(poly a,poly b){
int n=a.size(),m=b.size(),lim=1;
while(lim<=(n+m)) lim<<=1;
NTT(a,lim,1); NTT(b,lim,1);
rep(i,0,lim-1) ckmul(a[i],b[i]);
NTT(a,lim,-1);
a.resize(n+m-1);
return a;
}
inline poly Get_Line(int x){
vector<int> a,b; a.resize(x+1); b.resize(x+1);
for(int i=0;i<=x;++i){
if(i&1) a[i]=mod-ifac[i]; else a[i]=ifac[i];
b[i]=mul(ifac[i],ksm(i,x));
}
poly vec=Mul(a,b); vec.resize(x+1);
return vec;
}
inline poly solve(int l,int r){
if(l==r){
poly str=Get_Line(c[l]);
poly ret; ret.resize(c[l]+2);
rep(i,0,c[l]) ret[i+1]=mul(str[i],fac[i]);
return ret;
}
int mid=(l+r)>>1;
return Mul(solve(l,mid),solve(mid+1,r));
}
signed main(){
n=5e5; fac[0]=inv[0]=1;
for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],mod-2);
Down(i,n,1) ifac[i-1]=mul(ifac[i],i),inv[i]=mul(ifac[i],fac[i-1]);
n=read(); w=read();
int sumc=0;
rep(i,1,n) sumc+=(c[i]=read());
vector<int> f=solve(1,n);
int ans=0,dfac=1;
for(int i=0;i<=n+sumc;++i){
if(i-n>w) break;
if(i>=n){
ckadd(ans,mul(f[i],mul(dfac,ifac[i])));
}
ckmul(dfac,(w+n-i)%mod);
}
print(ans);
return 0;
}