• lucas定理 FOJ 2020 组合


     Problem 2020 组合

    Accept: 886    Submit: 2084
    Time Limit: 1000 mSec    Memory Limit : 32768 KB

    Problem Description

    给出组合数C(n,m), 表示从n个元素中选出m个元素的方案数。例如C(5,2) = 10, C(4,2) = 6.可是当n,m比较大的时候,C(n,m)很大!于是xiaobo希望你输出 C(n,m) mod p的值!

    Input

    输入数据第一行是一个正整数T,表示数据组数 (T <= 100) 接下来是T组数据,每组数据有3个正整数 n, m, p (1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数)

    Output

    对于每组数据,输出一个正整数,表示C(n,m) mod p的结果。

    Sample Input

    2 5 2 3 5 2 61

     Sample Output

    1 10 
    未预处理阶乘(在组合数函数中写了个循环):
     1 #include<iostream>
     2 using namespace std;
     3 #include<cstdio>
     4 #define ll long long
     5 int t;
     6 ll quick_mod(ll a,ll b,ll p)// a^b%p
     7 {
     8     a%=p;
     9     ll ans=1;
    10     while(b)
    11     {
    12         if(b&1)
    13         {
    14             b--;
    15             ans=(ans*a)%p;
    16         }
    17         b>>=1;
    18         a=(a*a)%p;
    19     }
    20     return ans;
    21 }
    22 ll C(ll n, ll m,ll p)
    23 {
    24     if(m>n) return 0;
    25     ll ans=1,a,b;
    26     for(int i=1;i<=m;++i)
    27     {
    28         a=(n+i-m)%p;
    29         b=i%p;
    30         ans=ans*(a*quick_mod(b,p-2,p)%p)%p;
    31     }
    32     return ans;
    33 }
    34 ll lucas(ll n,ll m,ll p)
    35 {
    36     if(m==0) return 1;
    37     return (lucas(n/p,m/p,p)*C(n%p,m%p,p))%p; 
    38 }
    39 int main()
    40 {
    41     scanf("%d",&t);
    42     while(t--)
    43     {
    44         ll n,m,p;
    45         cin>>n>>m>>p;
    46         cout<<lucas(n,m,p)<<endl;
    47     }
    48     return 0;
    49 }

    预处理阶乘(有时可以加快速度,相乘时也要防止溢出):

     1 /*事实上,这道题目预处理阶乘,反而会更慢,因为题目中n,m都是10^9,预处理已经接近超时了*/
     2 #include<iostream>
     3 using namespace std;
     4 #include<cstdio>
     5 #define S 10000000
     6 #define ll long long
     7 int t;
     8 long long f[1000000];
     9 void yuchuli(ll p)
    10 {
    11     f[0]=1;
    12     for(int i=1;i<=S;++i)
    13       f[i]=f[i-1]*i%p;
    14 }
    15 ll quick_mod(ll a,ll b,ll p)
    16 {
    17     a%=p;
    18     ll ans=1;
    19     while(b)
    20     {
    21         if(b&1)
    22         {
    23             b--;
    24             ans=(ans*a)%p;
    25         }
    26         b>>=1;
    27         a=(a*a)%p;
    28     }
    29     return ans;
    30 }
    31 ll C(ll n, ll m,ll p)
    32 {
    33     if(m>n) return 0;
    34     return (f[n]*quick(f[m]*f[n-m],p-2,p))%p;
    35 }
    36 ll lucas(ll n,ll m,ll p)
    37 {
    38     if(m==0) return 1;
    39     return (lucas(n/p,m/p,p)*C(n%p,m%p,p))%p; 
    40 }
    41 int main()
    42 {
    43     scanf("%d",&t);
    44     while(t--)
    45     {
    46         ll n,m,p;
    47         cin>>n>>m>>p;
    48         cout<<lucas(n,m,p)<<endl;
    49     }
    50     return 0;
    51 }
     
  • 相关阅读:
    POJ_1066_Treasure Hunt_判断线段相交
    【转载】VS写汇编程序01:VS2015配置汇编语言开发环境
    【转载】汇编调试程序Debug使用
    【转载】C++ STL快速入门
    Longest Palindromic Substring
    Leetcode经典试题:Longest Substring Without Repeating Characters解析
    C++数组的初始化
    C++题目:回文数判断
    C++-int类型整数超出范围后的处理
    Memorise Me!——用数值做地址,实现快速查找
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5517575.html
Copyright © 2020-2023  润新知