组合数问题

这里写图片描述
数据范围,我擦,看来查询只能O(1)啊
咋办啊
首先考虑,将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 int mod=1e9+7;
ll num[2000110]={0};
ll get_nts(ll x,ll y)
{
    ll ans=1;
    while(y)
    {
        if(y%2) ans=(ans*x)%mod;
        x=(x*x)%mod;
        y/=2;
    }
    return ans%mod;
}
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("test.out","w",stdout);
    num[1]=1; 
    for(int i=2;i<=2000000;i++)
     num[i]=(num[i-1]*i)%mod;
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        ll n;
        scanf("%lld",&n);
        ll ans=(num[2*n])*get_nts((num[n]*num[n])%mod,mod-2)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值