您的位置:首页 > 其它

排列组合 (组合数 思维题)

2017-08-22 15:26 288 查看

排列组合(pc.c/cpp/pas)

1 题目描述

T组数据,每次给定n,请求出下式的值,对10^9+7取模:

2 输入格式

第一行一个整数T,表示数据组数。

接下来T行,每一行包含一个整数n,含义如题所示。

3 输出格式

输出T行,每行包含一个整数,表示对10^9+7取模后的答案。

样例输入

2

1

2

样例输出

2

6

数据范围与约定

对于30%的数据,T<=500 , n<=10000。

对于100%的数据,T<=100000 , n<=1000000。

思路:

O(1)! O(1)! O(1)!

快找规律!! 找不到。怎么办。。。

猜答案!! 猜不到。怎么办。。。

爆零~~~

f(n) = C(n, 2n);

正文:

前30%的数据:存下阶乘以及阶乘的逆元,每次暴力做就好了。

前100%的数据:

这算是一道考察思维的题目,思路源自于一道文化课题目,原题的答案做法是暴力推式子。

当时想到了这样一个比较优秀的做法,对思维具有很好的启发作用,即考虑式子的组合意义。

首先考虑,将C(n,i)*C(n,i)换成C(n,i)*C(n,n-i)。

这样的话,就是对于每个i,计算n个中选i个的方案数乘上n个中选(n-i)个的方案数,最后累加起来。

这样得到的答案,实际上相当于2n个物品,在前n个中选i个,在后n个中选(n-i)个,

又由于i取遍0~n所有整数,那么累加后方案数就等于C(2n,n)。

所以每次输出C(2n,n)即可,同样预处理阶乘及逆元,复杂度O(n*log+T)。

实际上这道题打表找规律说不定也能找到规律。

#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;

const LL mod=1e9+7;

int T;
LL mub[2000010];

void init(int n){
mub[0]=1;
for(int i=1;i<=n;i++)
mub[i]=mub[i-1]*i%mod;
}

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

LL inverse( LL a ,LL n) {
LL x, y;
LL d = exgcd(a, n, x, y);
if(d == 1) return ( x % n + n ) % n;
else return -1;
}

LL solve(int x){
LL cc = inverse(mub[x], mod);
return mub[2*x] * cc % mod * cc % mod;
}

int main(){
freopen("pc.in","r",stdin);
freopen("pc.out","w",stdout);
init(2000010);
scanf("%d", &T);
while(T--){
int x;
scanf("%d",&x);
printf("%I64d\n", solve(x));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: