一开始题意没读懂,英语是硬伤,其实是这道题目真的有点饶人,后来补题,看懂了意思,从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 组合数 + 乘法逆元,布布扣,bubuko.com
Ural 1903 Unidentified Ships 组合数 + 乘法逆元
原文地址:http://blog.csdn.net/yitiaodacaidog/article/details/37960987