首页 > 代码库 > Ural 1903 Unidentified Ships 组合数 + 乘法逆元

Ural 1903 Unidentified Ships 组合数 + 乘法逆元

一开始题意没读懂,英语是硬伤,其实是这道题目真的有点饶人,后来补题,看懂了意思,从n个数中挑出t个,然后第k个必须要在,挑出的t个数要排序成不下降的顺序,然后 原本那个第k个数在这个跳出的t个数当中要在第x的位置


分析:直接找出比第k个数小的数的个数,还有比第k个数大的数的个数,当然啦还有可能存在与第k个数相等的数的个数,唉呀,一开始漏了相等的情况,没看题目案例,真是作死啊,后来全弄好了,那不就是在比它小的里面挑x-1个数字,当然也可以从相等的里面挑了补,然后在比它大的  里面挑t-x个数 当然也可以从相等的里面挑了补,然后就是理清楚关系就好了,每一次三个部分关系弄清楚 相乘 然后求总和, 一开始直接套了模版 大概需要开[5000][5000]的数组最起码,可是超了内存,没办法 其实C(5,4) == C(5,1)通过这个我们其实只需要构造二维一半即可那就是[5000][2500]的空间就够了,这样写一个即可,可是写了半天没写好,因为脑残了 忘了 c(5,0)的值为1,最后看了别人的构造才醒悟过来,真是脑残,当然除了这个方法 我们还可以使用直接求组合数的函数 的方法,因为这道题目要取模,而直接求组合数是涉及了除法的,除法对取模有影响,所以应该要转化为乘法,那就是求乘法逆元咯,

注释部分 是直接递推构造组合数的部分



题目:http://acm.timus.ru/problem.aspx?space=1&num=1903


#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>

#define ll long long

#define LL __int64

#define eps 1e-8

const int inf = 0xfffffff;

const ll INF = 1ll<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

const int MOD = 1000000007;

int t,n,k,x;

int num[5000 + 5];

int c[5000 + 5][2500 + 5];

//void C() { 
//	for(int i=0; i<=5000; ++i) {
//		c[i][0] = 1;
//	}
//	c[1][1] = 1;
//	for(int i=2; i<=5000; ++i) 
//		for(int j=1; j<=i/2; ++j)
//			c[i][j] = (c[i-1][min(j - 1,i - j)] + c[i-1][min(j,i - j - 1)]) % MOD;
//}

ll exgcd(ll a, ll b, ll &x, ll &y)  {
	if(!b) {
		x = 1; y = 0;
		return a;
	}
	ll r = exgcd(b, a%b, y, x);
	y -= a/b*x;
	return r;
}

ll inv(ll a, ll m)
{
	ll x,y,gcd = exgcd(a, m, x, y);
	if(x < 0)  
		x += m;
	return x;
}

ll C(ll n,ll m)//计算组合数C(n,m)
{
    ll t1=1,t2=1;
    for(LL i=n;i>m;i--)
    {
        t1=(t1*i)%MOD;
        t2=(t2*(i-m))%MOD;
    }
    return t1*inv(t2,MOD)%MOD;
}

int main() {
	/*C();*/
	while(scanf("%d %d",&n,&t) == 2) {
		for(int i=1;i<=n;i++)
			scanf("%d",&num[i]);
		scanf("%d %d",&k,&x);
		int lit = 0,big = 0,equ = 0;
		for(int i=1;i<=n;i++) {
			if(num[i] < num[k])
				lit++;
			else if(num[i] == num[k])
				equ++;
			else
				big++;
		}
		equ--;
		ll ans = 0ll;
		int left = x - 1;
		int right = t - x;
		for(int i=0;i<=min(lit,left);i++) {
			for(int j=0;j<=min(right,big);j++) {
				int k = t - i - j - 1;
				if(k < 0)break;
				if(k > equ)continue;
				if(i + k + 1< x)break;
				ll tmp = 1;
				/*int tx = c[lit][min(i,lit - i)];
				int ty = c[big][min(j,big - j)];

				tmp = tmp * c[lit][min(i,lit - i)] * c[big][min(j,big - j)] %MOD;

				int tz = c[equ][min(k,equ - k)];

				tmp = tmp * c[equ][min(k,equ - k)]%MOD;*/
				tmp = tmp * C(lit,min(i,lit - i)) * C(big,min(j,big - j)) %MOD;
				tmp = tmp * C(equ,min(k,equ - k))%MOD;
				ans += tmp;
				ans %= MOD;
			}
		}
		printf("%I64d\n",ans);
	}
	return 0;
}