A. Math Ball
题意
给定n个不同的小球,每种小球都有无穷多个,第i个小球有一个权值 c i c_{i} ci,现在你要从中选出不超过W个小球,定义其选择的权值为 ∑ k 1 + k 2 . . . . k n < = W ∏ i = 1 n k i c i \sum_{k_{1}+k_{2}....k_{n}<=W}\prod_{i=1}^{n}k_{i}^{c_{i}} ∑k1+k2....kn<=W∏i=1nkici,问所有选择方案的权值之和.
解析
考虑 f i ( x ) = ∑ j = 0 ∞ j c i x j f_{i}(x)=\sum_{j=0}^{\infin}j^{c_{i}}x^{j} fi(x)=∑j=0∞jcixj,则原式变为 ∑ i = 0 W [ x i ] ∏ j = 1 n f j ( x ) \sum_{i=0}^{W}[x^{i}]\prod_{j=1}^{n}f_{j}(x) ∑i=0W[xi]∏j=1nfj(x),乘上个 1 1 − x \frac{1}{1-x} 1−x1求个前缀和则变为 [ x W ] 1 1 − x ∏ j = 1 n f j ( x ) [x^{W}]\frac{1}{1-x}\prod_{j=1}^{n}f_{j}(x) [xW]1−x1∏j=1nfj(x),现在我们考虑如何处理 f i ( x ) f_{i}(x) fi(x)
考虑将自然数幂和展开 i k = ∑ j = 0 i { k j } j ! ( i j ) i^{k}=\sum_{j=0}^{i}{k\brace j}j!{\binom{i}{j}} ik=∑j=0i{jk}j!(ji)
则 f i ( x ) = ∑ j = 0 ∞ x j ∑ k = 0 j { c i k } k ! ( j k ) = ∑ k = 0 ∞ { c i k } k ! ∑ j = k ∞ x j ( j k ) f_{i}(x)=\sum_{j=0}^{\infin}x^{j}\sum_{k=0}^{j}{c_{i}\brace k}k!{\binom{j}{k}}=\sum_{k=0}^{\infin}{c_{i}\brace k}k!\sum_{j=k}^{\infin}x^{j}{\binom{j}{k}} fi(x)=∑j=0∞xj∑k=0j{kci}k!(kj)=∑k=0∞{kci}k!∑j=k∞xj(kj)
而我们知道 ∑ j = k ∞ x j ( j k ) = x k ( 1 − x ) k + 1 \sum_{j=k}^{\infin}x^{j}{\binom{j}{k}}=\frac{x^{k}}{(1-x)^{k+1}} ∑j=k∞xj(kj)=(1−x)k+1xk
所以原式可以转化为 f i ( x ) = ∑ k = 0 c i { c i k } k ! x k ( 1 − x ) k + 1 f_{i}(x)=\sum_{k=0}^{c_{i}}{c_{i}\brace k}k!\frac{x^{k}}{(1-x)^{k+1}} fi(x)=∑k=0ci{kci}k!(1−x)k+1xk
我们发现由于 ∑ i = 1 n c i < = 1 0 5 \sum_{i=1}^{n}c_{i}<=10^{5} ∑i=1nci<=105,所以 { c i k } {c_{i}\brace k} {kci}可以直接第二类斯特林数行就行了
我们设 g ( x ) = x 1 − x g(x)=\frac{x}{1-x} g(x)=1−xx,则 f i ( x ) = 1 1 − x ∑ k = 0 c i { c i k } k ! g ( x ) k f_{i}(x)= \frac{1}{1-x}\sum_{k=0}^{c_{i}}{c_{i}\brace k}k!g(x)^{k} fi(x)=1−x1∑k=0ci{kci}k!g(x)k
所以我们要求的就变成了 [ x W ] 1 ( 1 − x ) n + 1 ∑ k = 0 c 1 + c 2 . . . . c n A k g ( x ) k [x^{W}]\frac{1}{(1-x)^{n+1}}\sum_{k=0}^{c_{1}+c_{2}....c_{n}}A_{k}g(x)^{k} [xW](1−x)n+11∑k=0c1+c2....cnAkg(x)k
我们考虑对每一个 k k k,算出 [ x W ] 1 ( 1 − x ) n + 1 g ( x ) k [x^{W}]\frac{1}{(1-x)^{n+1}}g(x)^{k} [xW](1−x)n+11g(x)k,即 [ x W − k ] 1 ( 1 − x ) n + k + 1 [x^{W-k}]\frac{1}{(1-x)^{n+k+1}} [xW−k](1−x)n+k+11,直接广义二项式定理展开,答案为 ( W + n W − k ) \binom{W+n}{W-k} (W−kW+n)即 ( W + n n + k ) \binom{W+n}{n+k} (n+kW+n)
补充:如何计算第二类斯特林数行?
{ n m } n\brace m {mn}= ∑ i = 0 m ( m i ) ( − 1 ) i ( m − i ) n \sum_{i=0}^{m}\binom{m}{i}(-1)^{i}(m-i)^{n} ∑i=0m(im)(−1)i(m−i)n
#include<bits/stdc++.h>
#define ll long long
#define mk(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define cs const
using namespace std;
cs int g=3;
const int N=8e5+10;
const int mod=998244353;
typedef vector<int> poly;
int rev[N],inv[N],fac[N],invf[N];
int n,m,len,d,x,k;
poly a;
int mul(int x,int y){return (ll)x*y%mod;}
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y>=0?x-y:x-y+mod;}
int ksm(int x,int y){ll ans=1;for (;y;y>>=1,x=mul(x,x)) if (y&1) ans=mul(ans,x);return ans;
}
int read(){int f=1,x=0; char c=getchar();while (c<'0'||c>'9'){if (c=='-')f=-1;c=getchar();}while (c>='0'&&c<='9'){x=add(mul(x,10),c-'0');c=getchar();}return x;
}
int init(int x){int len=1,d=0;while (len<x) {len<<=1;d++;}for (int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(d-1));return len;
}
int BSGS(int X,int Y){int now=floor(sqrt(mod));int s=ksm(X,now);map<int,int>mp;int t=1;int sum=Y;for (int i=0;i<now;i++){mp[sum]=i; sum=mul(sum,X);}int s1=1;for (int i=0;i<mod;i+=now){s1=mul(s1,s);if (mp[s1]) return i+now-mp[s1];}return 0;
}
void prep(){inv[0]=inv[1]=1;for (int i=2;i<N;i++) inv[i]=mul(inv[mod%i],(mod-mod/i));invf[0]=1;for (int i=1;i<N;i++) invf[i]=mul(invf[i-1],inv[i]);fac[0]=1;for (int i=1;i<N;i++) fac[i]=mul(fac[i-1],i);
}
int lalala(int x){int now=BSGS(g,x);return ksm(g,now/2);
}
void out(poly a){for (int i=0;i<a.size();i++) printf("%d ",a[i]);puts("\n");
}
inline poly NTT(poly a,int t) {for (int i=0;i<a.size();i++) if (i<rev[i]) swap(a[i],a[rev[i]]);for (int i=1;i<a.size();i<<=1) {int s=(i<<1);int wn=ksm(g,(mod-1)/s);if (t==-1) wn=ksm(wn,mod-2);for (int j=0;j<a.size();j+=s) {int w=1;for (int k=j;k<j+i;k++) {int x=a[k],y=mul(a[k+i],w);a[k]=add(x,y); a[k+i]=dec(x,y);w=mul(w,wn);}}}if (t==-1){ll w=ksm(a.size(),mod-2);for (int i=0;i<a.size();i++) a[i]=mul(a[i],w);}return a;
}
inline poly get_down(poly a){for (int i=0;i<a.size()-1;i++) a[i]=mul(a[i+1],i+1);a.pop_back();return a;
}
inline poly get_up(poly a){a.push_back(0);for (int i=a.size()-1;i>0;i--) a[i]=mul(a[i-1],inv[i]);a[0]=0;return a;
}
inline poly operator +(poly a,poly b){a.resize(max(a.size(),b.size()));b.resize(max(a.size(),b.size()));for (int i=0;i<a.size();i++) a[i]=add(a[i],b[i]);return a;
}
inline poly operator -(poly a,poly b){a.resize(max(a.size(),b.size()));b.resize(max(a.size(),b.size()));for (int i=0;i<a.size();i++) a[i]=dec(a[i],b[i]);return a;
}
inline poly operator *(poly a,int x){x=(mod+x)%mod;for (int i=0;i<a.size();i++) a[i]=mul(a[i],x);return a;
}
inline poly shift(poly a,int x,int m){int n=(int)a.size();n-=x;if (n<=0) return poly(1,0);poly b(min(n,m),0);for (int i=max(0,-x);i<min(n,m);i++) b[i]=a[i+x];return b;
}
inline poly operator *(poly a,poly b){int n=a.size(),m=b.size(); int len=init(n+m-1);a.resize(len);b.resize(len);a=NTT(a,1); b=NTT(b,1);for (int i=0;i<a.size();i++) a[i]=mul(a[i],b[i]);a=NTT(a,-1);a.resize(n+m-1);return a;
}
inline poly get_inv(poly a){poly b,d;b.pb(ksm(a[0],mod-2)); d.pb(a[0]);int now=1;while (now<a.size()) {now<<=1; poly c=b;c=c*c;for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);c=c*d;c.resize(now); b=b*2; b=b-c;}b.resize(a.size());return b;
}
inline poly ln(poly a){poly c=get_up(get_inv(a)*get_down(a));c.resize(a.size());return c;}
inline poly exp(poly a){poly b,d;b.pb(1); d.pb(a[0]);int now=1;while (now<a.size()){now<<=1;for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);poly c=b;c.resize(now);c=ln(c)-d;for (int i=0;i<c.size();i++) c[i]=(mod-c[i])%mod;c[0]=add(c[0],1); b=b*c; b.resize(now); } b.resize(a.size());return b;
}
inline poly ksm(poly a,int k){int n=(int)a.size();int i=0;while (i<n&&!a[i]) i++;int v=a[i];a=a*ksm(v,mod-2);a=shift(a,i,n);a=exp(ln(a)*k);a=shift(a,-i*k,n);a=a*v;return a;
}
inline poly Sqrt(poly a){poly b,d;b.pb(lalala(a[0])); d.pb(a[0]);b[0]=min(b[0],mod-b[0]);int now=1;while (now<a.size()){now<<=1; poly c=b;for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);c.resize(now);c=get_inv(c);c=c*d;c.resize(now);b=b+c;for (int i=0;i<now;i++) b[i]=mul(b[i],inv[2]);}b.resize(a.size());return b;
}
long long W;
int c[N];
poly f[N];
poly Stirling2_row(int n){poly f(n+1,0),g(n+1,0);for (int i=0;i<=n;i++) if (i&1) f[i]=dec(0,invf[i]); else f[i]=invf[i];for (int i=0;i<=n;i++) g[i]=mul(ksm(i,n),invf[i]);f=f*g;f.resize(n+1);return f;
}
poly solve(int l,int r){if (l==r) return f[l];else{int mid=(l+r)/2;return solve(l,mid)*solve(mid+1,r);}
}
int main(){scanf("%d%lld",&n,&W);W%=mod;prep();for (int i=1;i<=n;i++) scanf("%d",&c[i]);for (int i=1;i<=n;i++){f[i]=Stirling2_row(c[i]);for (int j=0;j<f[i].size();j++) f[i][j]=mul(f[i][j],fac[j]);}poly ans=solve(1,n);int s=1;for (int i=1;i<=n;i++) s=1ll*((W+i)%mod)*s%mod*inv[i]%mod;int s_fin=0;for (int i=0;i<ans.size();i++){s_fin=add(s_fin,mul(s,ans[i]));s=mul(s,inv[n+i+1]);s=1ll*s*((W-i+mod)%mod)%mod;}printf("%d\n",s_fin);
}