1. 程式人生 > >【NOIP2016提高A組模擬9.17】小a的強迫癥

【NOIP2016提高A組模擬9.17】小a的強迫癥

ret include sin main img int 我們 scanf can

題目

技術分享圖片

分析

題目要求第i種顏色的最後一個珠子要在第i+1種顏色的最後一個珠子之前,
那麽我們從小到大枚舉做到第i種,把第i種的最後一顆珠子取出,將剩下的\(num(i)-1\)個珠子插入已排好的前i-1種中,再將取出的珠子放在最後一個。
每次求出將剩下的\(num(i)-1\)個珠子插入已排好的前i-1種中的方案數,將它乘以ans。
對於每個i的方案數可以用隔板問題來求。
但是,在比賽上,我忘了隔板問題,於是再枚舉個j,將已經排好的珠子分成j份,將要放進去的的\(num(i)-1\)個珠子找出j個空位(包括頭和尾),將這j份珠子放入j個空位。
結果搞了半天,唉,說多了都是淚啊。。。

註意預處理階乘,除法用逆元。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
const long long mo=998244353;
const long long N=100005;
using namespace std;
long long jc[N*10],a[N],sum[N],n,m,ans,ny[N*10];
long long c(long long m1,long long n1)
{
    return jc[m1]*ny[n1]%mo*ny[m1-n1]%mo;
}
long long mi(long long x,long long y)
{
    long long sum=1;
    while(y)
    {
        if(y&1) sum=sum*x%mo; 
        x=x*x%mo;
        y/=2;
    }
    return sum;
}
int main()
{
    jc[0]=1;
    for(long long i=1;i<=N*5-1;i++) jc[i]=jc[i-1]*i%mo;
    for(long long i=0;i<=N*5-1;i++) ny[i]=mi(jc[i],mo-2);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=a[i]+sum[i-1];
    }
    ans=1;
    for(int i=2;i<=n;i++)
    {
        long long k=0;
        for(long long j=1;j<=a[i] && j<=sum[i-1];j++)
        {
            k=(k+c(a[i],j)*((j==1)?1:c(sum[i-1]-1,j-1))%mo)%mo;
        }
        ans=(ans*k)%mo;
    }
    cout<<ans;
}

【NOIP2016提高A組模擬9.17】小a的強迫癥