Live2D

小a的强迫症(组合数学)

问题描述:

小a是一名强迫症患者,现在他要给一群带颜色的珠子排成一列,现在有N种颜色,其中第i种颜色的柱子有num(i)个。要求排列中第i种颜色珠子的最后一个珠子,一定要排在第i+1种颜色的最后一个珠子之前。问有多少种排列珠子的方案。

输入格式:

第一行:

一个整数N,表示珠子颜色数量

第二行:

N个整数,分别表示每种珠子的颜色数量

输出格式:

排列方案数,对998244353取余

思路:

对此,我要狠狠的揍一通我的电脑和我的脑子(电脑你为什么突然开不了机?我为什么本来想的是正解却超级复杂???)
其实这道题很水
对于第一次放进来的我们不管,因为它不管有多少,排列的方式都只有一种

从第二个开始我们就要更新答案

因为第二个的最后一个一定比第一个放的靠后

那我们就拿出一个默认放到最后,则前边就是一个长度为(前面已有长度+现在新到的物品的数量-1)的数列

但由于前面是已经排好的,顺序不用动,而新放进来的有相同,所以我们实际上就是在这个长度的序列中任选两个位置把这些塞进去即可

那这就是组合数的问题了(不要像我一样一开始先全排列后去重,那样麻烦的要死!!)

代码:

#include<iostream>
#include<cstdio>
#define p 998244353
#define rii register int i
#define rij register int j
using namespace std;
long long n,ans,zs,ny[500005],sl;
void qny()
{
    ny[1]=1;
    for(register int a=2;a<=500001;a++)
    {
        ny[a]=(p-(p/a))*ny[p%a]%p;
    }
}
long long zhsx(int m,int n)
{
    long long ltt=1;
    for(rii=1;i<=n;i++)
    {
        ltt*=ny[i];
        ltt%=p;
    }
    for(rii=m;i>=m-n+1;i--)
    {
        ltt*=i;
        ltt%=p;
    }
    return ltt;
}
int main()
{
//    freopen("qiang.in","r",stdin);
//    freopen("qiang.out","w",stdout);
    qny();
    scanf("%ld",&n);
    ans=1;
    for(rii=1;i<=n;i++)
    {
        scanf("%ld",&sl);
        if(i==1)
        {
            zs+=sl;
            continue;
        }
        ans*=zhsx(zs+sl-1,sl-1);
        ans%=p;
        zs+=sl;
    }
    cout<<ans;
}

 

posted @ 2018-07-10 16:47  ztz11  阅读(274)  评论(0编辑  收藏  举报