1. 程式人生 > >Ural 1903 Unidentified Ships 組合數 + 乘法逆元

Ural 1903 Unidentified Ships 組合數 + 乘法逆元

乘法逆元 內存 i++ targe dsm def ble pan bsp

一開始題意沒讀懂。英語是硬傷,事實上是這道題目真的有點饒人,後來補題,看懂了意思。從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;
}


Ural 1903 Unidentified Ships 組合數 + 乘法逆元