题意:开始输入两个数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
*/