有 n n n个物品,每个物品有 a i a_i ai件,要选择 k k k轮,每次可以选任意件物品,求本质不同的方案数
考虑当 n = 1 n=1 n=1时怎么做,我们把最后一位定义为第一位,以此类推
设 f i , j f_{i,j} fi,j表示当前进行到第 i i i位,可供选择的数字有 j j j个,令 s = ∑ a i + 1 s=\sum a_i+1 s=∑ai+1,则有
一位: f 1 , s = s f_{1,s}=s f1,s=s
二位: f 2 , s = ∑ i = 1 s i f_{2,s}=\sum _{i=1}^{s} i f2,s=∑i=1si
三位: f 3 , s = ∑ j = 1 s ∑ i = 1 j i f_{3,s}=\sum_{j=1}^s\sum _{i=1}^j i f3,s=∑j=1s∑i=1ji
四位: f 4 , s = ∑ k = 1 s ∑ j = 1 k ∑ i = 1 j i f_{4,s}=\sum _{k=1}^s \sum_{j=1}^k \sum_{i=1}^j i f4,s=∑k=1s∑j=1k∑i=1ji
得到递推式
i i i位: f i , j = ∑ l = 1 j f i − 1 , l f_{i,j}=\sum_{l=1}^j f_{i-1,l} fi,j=∑l=1jfi−1,l
这样子是 O ( k s 2 ) O(ks^2) O(ks2)的,考虑看一下 f i , j f_{i,j} fi,j与 f i , j − 1 f_{i,j-1} fi,j−1的关系,得到了
f i , j = f i , j − 1 + f i − 1 , j f_{i,j}=f_{i,j-1}+f_{i-1,j} fi,j=fi,j−1+fi−1,j
就 O ( k s ) O(ks) O(ks)了,还是30分
基于 30 p t s 30pts 30pts
发现这个式子很像前缀和的形式,于是我们令 p i , j = ∑ k = 1 j f i , k p_{i,j}=\sum _{k=1}^j f_{i,k} pi,j=∑k=1jfi,k
则 p i , j = p i , j − 1 + f i , j p_{i,j}=p_{i,j-1}+f_{i,j} pi,j=pi,j−1+fi,j
f i , j = p i − 1 , j f_{i,j}=p_{i-1,j} fi,j=pi−1,j
我们把 f f f接到 p p p的后面,然后做矩阵乘法,可以得到 50 p t s 50pts 50pts【实测只有30,野鸡OJ太垃圾了】
基于 30 p t s 30pts 30pts
注意到 f f f的方程相当于可以从上边和左边转移,也就是组合数 C k + a i a i C_{k+a_i}^{a_i} Ck+aiai(每一步可以向上或向左边揍)
然后又发现 a i a_i ai间互不干扰,直接乘起来即可
时间复杂度: O ( n a i ) O(na_i) O(nai)(可以通过预处理做到 O ( n + a i ) O(n+a_i) O(n+ai))
#include
#include
#include
#include
#define LL long long
#define mod 998244353
using namespace std;int n,s;
LL fac[110],inv[110],k,Ans=1,a[100011];
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline LL ksm(LL x,LL y)
{
LL res=1;
for(;y;y>>=1,(x*=x)%=mod) if(y&1) (res*=x)%=mod;
return res;
}
signed main()
{
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(register int i=2;i<=100;i++) fac[i]=fac[i-1]*i%mod;
inv[100]=ksm(fac[100],mod-2);
for(register int i=99;i>1;i--) inv[i]=(1ll*inv[i+1]*(i+1))%mod;
n=read();k=read();
for(register int i=1;i<=n;i++)
{
a[i]=read();
for(register int j=0;j<a[i];j++) (Ans*=(k+a[i]-j+mod)%mod)%=mod;
(Ans*=inv[a[i]])%=mod;
}
printf("%lld",Ans);
}