小a的强迫症 题解

题面:

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;
}

 

posted @ 2019-11-07 20:41  神之右大臣  阅读(142)  评论(0编辑  收藏  举报