• 组合数的求解(打表,逆元,Lucas 定理,大整数求解)


    885. 求组合数 I

    给定 n

    组询问,每组询问给定两个整数 a,b,请你输出 Cbamod(109+7)

    的值。

    输入格式

    第一行包含整数 n

    接下来 n

    行,每行包含一组 a 和 b

    输出格式

    共 n

    行,每行输出一个询问的解。

    数据范围

    1≤n≤10000

    ,
    1≤b≤a≤2000

    输入样例:

    1. 3
    2. 3 1
    3. 5 3
    4. 2 2

    输出样例:

    1. 3
    2. 10
    3. 1

     coding:

    由于1 ≤ b ≤ a ≤ 2000;所以可以用二维数组把所有组合数的值都存储下来,

    1. /**
    2. * 由于1 ≤ b ≤ a ≤ 2000;所以可以用二维数组把所有组合数的值都存储下来,
    3. */
    4. #include
    5. using namespace std;
    6. const int maxn=2010 , mod=1e9+7;
    7. int C[maxn][maxn];
    8. void init()
    9. {
    10. for(int i=0;i
    11. {
    12. C[i][0]=1;
    13. C[i][i]=1;
    14. }
    15. for(int i=2;i
    16. for(int j=1;j<=i/2;++j)
    17. {
    18. C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    19. C[i][i-j]=C[i][j];
    20. }
    21. }
    22. int main()
    23. {
    24. init();
    25. int n;
    26. cin >> n;
    27. while (n -- )
    28. {
    29. int a,b;
    30. cin >> a >> b;
    31. cout << C[a][b] << endl;
    32. }
    33. return 0;
    34. }

    886. 求组合数 II

    给定 n

    组询问,每组询问给定两个整数 a,b,请你输出 Cbamod(109+7)

    的值。

    输入格式

    第一行包含整数 n

    接下来 n

    行,每行包含一组 a 和 b

    输出格式

    共 n

    行,每行输出一个询问的解。

    数据范围

    1≤n≤10000

    ,
    1≤b≤a≤105

    输入样例:

    1. 3
    2. 3 1
    3. 5 3
    4. 2 2

    输出样例:

    1. 3
    2. 10
    3. 1

    假设 a,b,m都是整数,m>1,且ab与1模m同余,则a与b互为模m的逆元。
     * 所以当m为质数的时候,a的m-2次方就是a模m的逆元。(费马小定理)。
     *
     * C(a,b)%mod= a!/(b!*(a-b)!)%mod;
     * 由于1 ≤ b ≤ a ≤ 10^5,所以可以预处理出fac[maxn],infac[maxn](阶乘的结果,阶乘的逆元的结果)
     * 结果直接用逆元进行计算。

    1. /**
    2. * 假设 a,b,m都是整数,m>1,且ab与1模m同余,则a与b互为模m的逆元。
    3. * 所以当m为质数的时候,a的m-2次方就是a模m的逆元。(费马小定理)。
    4. *
    5. * C(a,b)%mod= a!/(b!*(a-b)!)%mod;
    6. * 由于1 ≤ b ≤ a ≤ 10^5,所以可以预处理出fac[maxn],infac[maxn](阶乘的结果,阶乘的逆元的结果)
    7. * 结果直接用逆元进行计算。
    8. */
    9. #include
    10. using namespace std;
    11. typedef long long LL;
    12. const int maxn=1e5+10,mod=1e9+7;
    13. int fac[maxn],infac[maxn];
    14. int qmi(int a,int b,int p) //a^b%p
    15. {
    16. int res=1;
    17. while(b)
    18. {
    19. if(b&1)
    20. res=(LL)res*a%p;
    21. a=(LL)a*a%p;
    22. b>>=1;
    23. }
    24. return res;
    25. }
    26. void init()
    27. {
    28. fac[0]=infac[0]=1;
    29. for(int i=1;i//求阶乘的结果及阶乘的逆元的结果
    30. {
    31. fac[i]=(LL)fac[i-1]*i%mod;
    32. infac[i]=(LL)infac[i-1]*qmi(i,mod-2,mod)%mod;
    33. }
    34. }
    35. int main()
    36. {
    37. init();
    38. int n;
    39. cin >> n;
    40. while (n -- )
    41. {
    42. int a,b;
    43. cin >> a >> b;
    44. cout << (LL)fac[a] * infac[b] % mod * infac[a-b] % mod << endl;
    45. }
    46. return 0;
    47. }

    887. 求组合数 III

    给定 n

    组询问,每组询问给定三个整数 a,b,p,其中 p 是质数,请你输出 Cbamodp

    的值。

    输入格式

    第一行包含整数 n

    接下来 n

    行,每行包含一组 a,b,p

    输出格式

    共 n

    行,每行输出一个询问的解。

    数据范围

    1≤n≤20

    ,
    1≤b≤a≤1018,
    1≤p≤105

    ,

    输入样例:

    1. 3
    2. 5 3 7
    3. 3 1 5
    4. 6 4 13

    输出样例:

    1. 3
    2. 3
    3. 2

     证明如下:

     

     

     

    1. #include
    2. using namespace std;
    3. typedef long long LL;
    4. int qmi(int a,int b,int p)
    5. {
    6. int res=1;
    7. while(b)
    8. {
    9. if(b&1)
    10. res=(LL)res*a%p;
    11. a=(LL)a*a%p;
    12. b>>=1;
    13. }
    14. return res;
    15. }
    16. int CP(int a,int b,int p)
    17. {
    18. int res=1;
    19. for(int i=1;i<=b;++i)
    20. {
    21. res=(LL)res*(a-b+i) % p;
    22. res=(LL)res*qmi(i,p-2,p) % p; //根据费马小定理用逆元求解
    23. }
    24. return res;
    25. }
    26. int Lucas(LL a,LL b,int p)
    27. {
    28. if(a
    29. return CP(a,b,p);
    30. else
    31. return (LL)CP(a%p,b%p,p) * Lucas(a/p,b/p,p) % p;
    32. }
    33. int main()
    34. {
    35. int n;
    36. cin >> n;
    37. while (n -- )
    38. {
    39. LL a,b;
    40. int p;
    41. cin >> a >> b >>p;
    42. cout << Lucas(a,b,p) << endl;
    43. }
    44. return 0;
    45. }

    将求逆元的过程拿到for循环外面能快一个数量级不止。

    如果CP函数这么写,还能快上一倍:

    int CP(int a,int b,int p)
    {
        if(a         return 0;
        int mul=a-b;  //假设b < a-b
        if((a-b) < b) //如果a-b < a,那么还得改变mul和b 的值;(原因是使求阶乘的运算步骤最少)
        {
            mul=b;
            b=a-b;
        }
        
        LL x=1,y=1;
        for(int i=1;i<=b;++i)
        {
            x=(mul+i)*x%p;  //先分别求分子与分母的阶乘,最后再用逆元求结果
            y=y*i%p;
        }
        
        return x*qmi(y,p-2,p) %p;  //用逆元求结果
    }

     将求逆元的过程拿到for循环外面:

    1. #include
    2. using namespace std;
    3. typedef long long LL;
    4. int qmi(int a,int b,int p)
    5. {
    6. int res=1;
    7. while(b)
    8. {
    9. if(b&1)
    10. res=(LL)res*a%p;
    11. a=(LL)a*a%p;
    12. b>>=1;
    13. }
    14. return res;
    15. }
    16. int CP(int a,int b,int p)
    17. {
    18. LL x=1,y=1;
    19. for(int i=1;i<=b;++i)
    20. {
    21. x=x*(a-b+i) % p;
    22. y=y*i % p;
    23. }
    24. return x*qmi(y,p-2,p)%p;
    25. }
    26. int Lucas(LL a,LL b,int p)
    27. {
    28. if(a
    29. return CP(a,b,p);
    30. else
    31. return (LL)CP(a%p,b%p,p) * Lucas(a/p,b/p,p) % p;
    32. }
    33. int main()
    34. {
    35. int n;
    36. cin >> n;
    37. while (n -- )
    38. {
    39. LL a,b;
    40. int p;
    41. cin >> a >> b >>p;
    42. cout << Lucas(a,b,p) << endl;
    43. }
    44. return 0;
    45. }

    888. 求组合数 IV

    输入 a,b

    ,求 Cba

    的值。

    注意结果可能很大,需要使用高精度计算。

    输入格式

    共一行,包含两个整数 a

    和 b

    输出格式

    共一行,输出 Cba

    的值。

    数据范围

    1≤b≤a≤5000

    输入样例:

    5 3
    

    输出样例:

    10
    

    C(a,b) 是个整数,那么我们一定能进行质因数分解;
     * 同样,C(a,b)=a!/(b!*(a-b)!),我们可以把分母与分子也进行质因数分解,
     * 将分子与分母相同的质因子进行指数相减,最后将所有得到的质因数进行相乘,
     * 就能得到最后的结果。
     *
     * 将分子与分母相同的质因子进行指数相减得到的指数一定是大于等于0的吗?
     * 证明:假定存在质因子相减得到的指数小于0的质因子,那么分母一定存在一个
     * 质因子,它与任何质因子都是互质的,因此C(a,b) 的结果就以应该是小数,而不是
     * 整数,这与C(a,b) 应该为整数矛盾,所以将分子与分母相同的质因子进行指数相减
     * 得到的指数一定是大于等于0的,得证!

    1. /**
    2. * C(a,b) 是个整数,那么我们一定能进行质因数分解;
    3. * 同样,C(a,b)=a!/(b!*(a-b)!),我们可以把分母与分子也进行质因数分解,
    4. * 将分子与分母相同的质因子进行指数相减,最后将所有得到的质因数进行相乘,
    5. * 就能得到最后的结果。
    6. *
    7. * 将分子与分母相同的质因子进行指数相减得到的指数一定是大于等于0的吗?
    8. * 证明:假定存在质因子相减得到的指数小于0的质因子,那么分母一定存在一个
    9. * 质因子,它与任何质因子都是互质的,因此C(a,b) 的结果就以应该是小数,而不是
    10. * 整数,这与C(a,b) 应该为整数矛盾,所以将分子与分母相同的质因子进行指数相减
    11. * 得到的指数一定是大于等于0的,得证!
    12. */
    13. #include
    14. #include
    15. using namespace std;
    16. const int maxn=5010;
    17. int p[maxn] ,num=0 , sum[maxn]; //p存素数,sum素数的指数
    18. bool hs[maxn];
    19. void get_primer(int n); //获得n以内的素数
    20. int cal(int a,int p); //a! 内有多少个 质因子p
    21. void get_pow(int a,int b); //获得C(a,b)内的 质因子的指数
    22. vector<int> mul(vector<int> &A,int b); //高精度与整数的乘法
    23. int main()
    24. {
    25. int a,b;
    26. cin >> a >> b;
    27. get_primer(a);
    28. get_pow(a,b);
    29. vector<int> res;
    30. res.push_back(1);
    31. for(int i=0;i
    32. for(int j=0;j
    33. res=mul(res,p[i]);
    34. for(int i=res.size()-1;i>=0;--i)
    35. cout << res[i];
    36. return 0;
    37. }
    38. void get_primer(int n) //获得n以内的素数
    39. {
    40. for(int i=2;i<=n;++i)
    41. {
    42. if(!hs[i])
    43. p[num++]=i;
    44. for(int j=0;p[j] <= n/i;++j)
    45. {
    46. hs[p[j]*i]=1;
    47. if(i%p[j]==0)
    48. break;
    49. }
    50. }
    51. }
    52. int cal(int a,int p) // a! 内有多少个 质因子p
    53. {
    54. if(a
    55. return 0;
    56. else
    57. return cal(a/p,p) + a/p ;
    58. }
    59. void get_pow(int a,int b) //获得C(a,b)内的 质因子的指数
    60. {
    61. for(int i=0;i
    62. {
    63. int cnt=cal(a,p[i]) - cal(a-b,p[i]) - cal(b,p[i]);
    64. sum[i]=cnt;
    65. }
    66. }
    67. vector<int> mul(vector<int> &A,int b) //高精度与整数的乘法
    68. {
    69. vector<int> res;
    70. int d=0;
    71. for(int i=0;isize();++i)
    72. {
    73. d+=A[i]*b;
    74. res.push_back(d%10);
    75. d/=10;
    76. }
    77. while(d)
    78. {
    79. res.push_back(d%10);
    80. d/=10;
    81. }
    82. return res;
    83. }

  • 相关阅读:
    视频画面噪点太多难处理?AI工具一键消除
    B站:AB test [下]
    HBase学习笔记
    物体6D位姿估计方法总结
    Hadoop(HDFS)
    d3dx9_43.dll缺失怎么办?教你一分钟修复d3dx9_43.dll丢失问题
    [附源码]Python计算机毕业设计Django的项目管理系统
    数字样机的前世今生
    【算法练习Day27】买卖股票的最佳时机 II&&跳跃游戏&&跳跃游戏 II
    2022杭电多校 第一场 个人题解(ABCDIHK)
  • 原文地址:https://blog.csdn.net/qq_51825761/article/details/126305599