https://jzoj.net/senior/#main/show/4786
题解:
设num[i]为i种珍珠的个数
假设前(i-1)种珠子都摆放好,其方案数为f[i-1],要求f[i]
因题意,第i种的一个要放最后面
放完后还剩num[i]-1个i种珍珠
可以放进球与球的间隙中。
如图,可以放进1~4号间隙的任何一个。
再放入一个后。
就有5个空隙可以放了,以此类推。
让人联想到插板问题。
因此f[i] = f[i-1] * 插板方案。
设1~i-1种小球有q个
插板方案数 = C(q+num[i]-1,num[i]-1)
这样算就行了。
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof (a))
#define ll long long
#define mod 998244353
#define N 500010
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
ll n,i,j,ans,t,tot,inv;
ll a[N],bz[N],pre[N],w[N],fact[N],factinv[N];
ll sqr(ll x){return x*x%mod;}
ll power(ll x,ll p)
{
ll z=1;
while(p)
{
if(p&1)(z*=x)%=mod;
(x*=x)%=mod;
p>>=1;
}
return z;
}
void init()
{
fact[0]=1;
for(i=1;i<=pre[n];i++)
fact[i] = fact[i-1] * i % mod;
factinv[pre[n]] = power(fact[pre[n]],mod-2);
for(i=pre[n]-1;i>=0;i--) factinv[i] = factinv[i+1] * (i+1) % mod;
return ;
}
ll C(ll m,ll n)
{
return fact[m] * factinv[n] % mod * factinv[m-n] % mod;
}
void work()
{
w[1]=1;
for(i=2;i<=n;i++)
w[i] = w[i-1] * C(a[i]+pre[i-1]-1,a[i]-1)%mod;
}
int main()
{
scanf("%lld",&n);
for(i=1;i<=n;i++)scanf("%lld",&a[i]);
for(i=1;i<=n;i++)pre[i] = pre[i-1]+a[i];
init();
work();
ans = w[n];
printf("%lld\n",ans);
return 0;
}
O(n)