题目:
题解:
前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<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int p=1000000007;
int jc[2000005],ni[2000005],T;
int pow(int a,int b)
{
int re=1,t=a;
while(b)
{
if(b&1) re=1ll*re*t%p;
t=1ll*t*t%p;
b>>=1;
}
return re;
}
ll C(int n,int m)
{
return 1ll*jc[n]*ni[m]%p*ni[n-m]%p;
}
int main()
{
jc[0]=1;
for(int i=1;i<=2000001;i++) jc[i]=1ll*jc[i-1]*i%p;
ni[2000001]=pow(jc[2000001],p-2);
for(int i=2000000;i>=0;i--) ni[i]=1ll*ni[i+1]*(i+1)%p;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
if(n==0) printf("1\n");
else printf("%lld\n",2*C(2*n-1,n)%p);
}
return 0;
}