小a的学期 求C(n,m)%p

链接:https://ac.nowcoder.com/acm/contest/317/H
来源:牛客网
 

小a的学期

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

小a是一个健忘的人,由于他经常忘记做作业,因此老师对他很恼火。
小a马上就要开学了,他学期一共2n2n天,对于第ii天,他有可能写了作业,也可能没写作业,不过他自己心里还有点B数,因此他会写恰好nn天的作业
现在,小a需要安排他的学期计划,如果小a的学期中存在一天xx,在这之前的xx天中,他没写作业的天数 - 写作业的天数⩾k⩾k,那么老师就会把它开除,我们称这是一种不合法的方案
小a想知道他有多少种合法的方案

输入描述:

第一行三个整数n,k,pn,k,p,pp表示对pp取模

输出描述:

一个整数表示答案

示例1

输入

2 1 100007

输出

2

说明

总共有2n=42n=4天
合法的方案有
写了 没写 写了 没写
写了 写了 没写 没写
注意:没写 写了 没写 写了 是一种不合法的方案,因为在第一天时没写的天数-写了的天数⩾1⩾1

示例2

输入

10 5 10000007

输出

169252

备注:

1⩽n,k⩽106,p⩽109+71⩽n,k⩽106,p⩽109+7
不保证pp为质数!

 //求(C(n*2,n)-C(n*2,n+k))%p;

模板题,但是模板选错了,一直WA!!!

使用素数去重,然后计算结果

This is the code

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define EPS 1e-8
#define MOD 1e9+7
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x7f7f7f7f      //2139062143
#define LL_INF 0x7f7f7f7f7f7f7f7f //9187201950435737471
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int MAXN = 2e6+6;
vector<LL > prim;
bool not_prime[MAXN|5];
//用筛法生成素数
void Prime()
{
    for(LL i=2; i<MAXN; ++i)
    {
        if(!not_prime[i])
            prim.push_back(i);
        for(int j=0; j<prim.size()&&prim[j]*i<MAXN; ++j)
        {
            not_prime[prim[j]*i]=1;
            if(!(i%prim[j]))//保证没有重复筛选
                break;
        }
    }
}
//计算n!中素因子p的指数
LL Cal(LL x, LL p)
{
    LL ret=0;
    LL rec= p;
    while(x>=rec)
    {
        ret+=x/rec;
        rec*=p;
    }
    return ret;
}

//计算n的k次方对M取模,二分法
LL Pow(LL n, LL k, LL M)
{
    LL ret = 1;
    while(k)
    {
        if(k&1)
            ret=(ret*n)%M;
        n=(n*n)%M;
        k>>=1;
    }
    return ret;
}

//计算C(n,m)%M
LL C(LL n,LL m,LL M)
{
    LL ans=1;
    LL num;
    for(int i=0; i<prim.size() && prim[i]<=n; ++i)
    {
        num=Cal(n, prim[i])-Cal(m, prim[i])-Cal(n-m, prim[i]);
        ans=(ans*Pow(prim[i], num, M))%M;
    }
    return ans%M;
}

int main()
{
    Prime();
    LL n,m,M;
    scanf("%lld%lld%lld",&n,&m,&M);
    printf("%lld\n",(C(2*n,n,M)-C(2*n,n+m,M)+M)%M);
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值