题面:
小a是一名强迫症患者,现在他要给一群带颜色的珠子排成一列,现在有N种颜色,其中第i种颜色的柱子有num(i)个。要求排列中第i种颜色珠子的最后一个珠子,一定要排在第i+1种颜色的最后一个珠子之前。问有多少种排列珠子的方案。
输入格式
第一行一个整数N,表示珠子颜色数量第二行N个整数,分别表示每种珠子的颜色数量
输出格式
排列方案数,对998244353取余
样例输入
3
2 2 1
样例输出
3
数据规模及约定
共3种排列方案:
12123
11223
21123
对于40%的数据,所有珠子数量和小于15
对于80%的数据,N<=1000,所有珠子数量和小于5000
对于100%的数据,N<=100000,所有珠子数量和小于500000
首先这是一道组合数的题无疑了;
然后就是怎么求;
设f[i]是在放了前i个数的方案数;
显然地:对于新的一个种类的数i,我们可以把它的(num[i]-1)个插入到前(sum[i]-1)个空中,且没有任何特殊限制;
那么我们就可以得到方程:
f[i]=f[i-1]*C(sum[i]-1,num[i]-1);
这道题线不线性求逆元都无所谓啦~
#include <bits/stdc++.h> #define p 998244353 #define inc(i,a,b) for(register int i=a;i<=b;i++) using namespace std; int a[100010]; int n,tot; long long f[100010]; long long KSM(long long a,long long b) { long long res=1; while(b){ if(b&1) res=res*a%p; a=a*a%p; b/=2; } return res; } long long pre[500010]; long long C(long long a,long long b) { long long tmp=pre[a]*KSM(pre[b]*pre[(a-b)]%p,p-2)%p; return tmp%p; } int main() { cin>>n; inc(i,1,n){ scanf("%d",&a[i]); } pre[0]=1; inc(i,1,500010) pre[i]=pre[i-1]*i%p; f[0]=1; inc(i,1,n){ tot+=a[i]; f[i]=(f[i-1]*C(tot-1,a[i]-1))%p; } cout<<f[n]%p; }