URAL 1903 Unidentified Ships 组合数

10 篇文章 0 订阅

题意:开始输入两个数n和t,分别表示进入多维空间前后的飞船数,之后n个数表示n艘类别,之后两个数k和x表示n个飞船中第k个飞船,其余飞船进入多维空间后,剩余的t艘飞船中排第x位,这t艘飞船按类别从小到大排列。求的问题是剩余的t艘飞船有多少种可能组合。

题解:一开始记录比第k艘类别大于,等于,小于的飞船数gr,eq,le。在找出x位置前后的空余b,d。结果就是∑(C(eq,i)*C(le,b-i)*C(gr,d)+...+C(eq,i)*C(le,b)*C(gr,d-i))(eq>=i>=0),单纯的组合数。


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL __int64
const LL maxn=5e3+5;
const LL mod=1e9+7;
LL a[maxn],f[maxn],g[maxn],h[maxn];
LL pow_mod(LL a,LL b,LL n)//a^b%n
{
    LL s=1;
    while(b)
    {
        if(b&1)
            s=(s*a)%n;
        a=(a*a)%n;
        b=b>>1;
    }
    return s;
}
//大小比较,__int64不能直接用,哎
LL max(LL a,LL b)
{
    return a>b?a:b;
}
LL min(LL a,LL b)
{
    return a<b?a:b;
}
int main()
{
    LL n,t;
    while(scanf("%I64d%I64d",&n,&t)!=EOF)
    {
        LL i,j,k,x,eq,gr,le,b,c,d;
        for(i=0;i<n;i++)
            scanf("%I64d",&a[i]);
        scanf("%I64d%I64d",&k,&x);
        eq=gr=le=0;
        //计数
        for(i=0;i<n;i++)
        {
            if(a[i]==a[k-1])eq++;
            else if(a[i]<a[k-1])le++;
            else gr++;
        }
        eq--;
        b=x-1;
        d=t-x;
        LL ans=0;
        f[0]=g[0]=h[0]=1;
        //列举出所有C(le,0),...,C(le,le),C(eq,0),...,C(eq,eq),C(gr,0),...,C(gr,gr)
        for(i=1;i<=le;i++)
        {
            if(le-i<i)f[i]=f[le-i];
            else f[i]=(f[i-1]*(le-i+1)%mod*pow_mod(i,mod-2,mod))%mod;//le的组合数
        }
        for(i=1;i<=gr;i++)
        {
            if(gr-i<i)g[i]=g[gr-i];
            else g[i]=(g[i-1]*(gr-i+1)%mod*pow_mod(i,mod-2,mod))%mod;//gr的组合数
        }
        for(i=1;i<=eq;i++)
        {
            if(eq-i<i)h[i]=h[eq-i];
            else h[i]=(h[i-1]*(eq-i+1)%mod*pow_mod(i,mod-2,mod))%mod;//eq的组合数
        }
        
        //题解中的公式
        for(i=0;i<=eq;i++)
        {
            for(j=0;j<=i;j++)
            {
                if(b-j<0)break;
                k=d-i+j;
                if(k<0)continue;
                    ans=(ans+h[i]*f[b-j]%mod*g[k])%mod;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
/*
5 3
1 3 3 3 5
3 2
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值