Description

【NOIP模拟】小a的强迫症_小a的强迫症

Solution

由于组合数的基础不好,这题怎么想都想不出来。
但是有一个很显然的东西很容易看出来,最后一个颜色的柱子肯定要放在最后面。
那么现在只有n-1个位置了,最后一个颜色的柱子只剩下a[n]-1个了,但是这a[n]-1个可以随便乱放(很显然),那么贡献:Ca[n]−1n−1,然后考虑倒数第二个颜色,因为倒数第一个已经放完了,那么就会留下一些空,这些空的最后一个一定要把倒数第二个颜色放上去(很显然),那么倒数第二个也只剩下a[n-1]-1个了,格子数也只剩下n-a[n]-1个了,那么倒数第二个颜色的贡献就是Ca[n−1]−1n−a[n]−1,然后以此类推……
最后答案就是∏1i=nCa[i]−1n−∑nj=i+1a[j]−1,预处理一下,逆元用线性的求,O(n)就搞定了。

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=500007,mo=998244353;
ll i,j,k,l,t,n,m,ans,cas,shu;
ll a[maxn];
ll fact[maxn],ni[maxn];
ll qsm(ll x,ll y){
ll z=1;
while(y){
if(y&1)z=z*x%mo;
x=x*x%mo;
y/=2;
}
return z;
}
ll c(ll x,ll y){
return fact[x]*ni[y]%mo*ni[x-y]%mo;
}
int main(){
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]),shu+=a[i];
fact[0]=ni[0]=1;
fo(i,1,shu)fact[i]=fact[i-1]*i%mo;
ni[shu]=qsm(fact[shu],mo-2);
fod(i,shu-1,1)ni[i]=ni[i+1]*(i+1)%mo;
ans=1;t=1;
fod(i,n,1){
ans=ans*c(shu-t,a[i]-1)%mo;
t+=a[i];
}
printf("%lld\n",ans);
}