• 组合数的末十位


    题目描述

    求出C(n,r)的最后十位,其中0<r≤n≤30000,输出时不足十位数也按十位输出,此时高位用0表示。C(n,r)=n×(n-1)×……×(n-r+1)/(1×2×3×……×r)

    输入数据为两个以空格隔开的自然数nr

    输入

    一行两个整数

    输出

    一行,10位数字

    样例输入

    5 2

    样例输出

    0000000010

    这道题我第一次看顿时就觉得变态至极,这不就是高精乘然后高精除以高精吗?!然后磨蹭了半天最后还是跪在高精除以高精了…………

    最后看了下标程……………………

    差点吐血…………………………

    咳咳,首先这道题是组合数,那也就是说一定能整除,那我们能不能先去约分?这样就说不定避免了高精除了。

    约分这回事,标程非常妙。首先他将分子全部分解质因数,然后将分母也不断分解质因数,分母分解的同时就可以用他的质因数来约分了。这样分母分解完后,剩下的质因数就全部是答案的了。

    再具体讲一下,首先开一个数组a,记录质因数,a[i] 代表的就是质因数 i 的个数。因为 n <= 30000,所以 a 开30000就足够了。

    对于分子,找到一个质因数 i 就 a[i]++。而且因为分子是一堆数的乘积,所以将每一个乘数分解就行,不要都乘起来再分解,那肯定会爆 long long。

    对于分母,也是同理,只不过找到一个 i 就 a[i]--,这就相当于约分了,妙。

    最后a数组中非0的 a[i] 的就是答案的质因数了。

    不过还要说一下答案。理论上把 a 数组中剩下的都乘起来就行了(高精乘),但是别忘了我们只用输出后十位,所以保守一点算出后20位就行了,到了20就停。这样就大大节省了时间,而且存答案的数组只用开到21就足够了。

     1 #include <iostream>
     2 #include <cstring>
     3 #include<algorithm>
     4 #include <cstdio>
     5 #include <cmath>
     6 using namespace std;
     7 const int max_size = 3e4 + 5;
     8 const int maxn = 20; 
     9 int a[max_size], b[maxn + 5];
    10 int n, r;
    11 void divide(int n)         //约分 
    12 {
    13     for(int m = 2; m * m <= n; ++m)
    14     {
    15         while (n % m == 0 && n!= 0) 
    16         {
    17             n /= m;
    18             a[m]--;
    19         }
    20     }
    21     a[n]--;
    22 }
    23 void fenjie(int n)         //a[]记录分子质因数 
    24 {
    25     for(int m = 2; m * m <= n; ++m)        
    26     {
    27         while(n % m == 0 && n != 0) 
    28         {
    29             n /= m;
    30             a[m]++;
    31         }
    32     }
    33     a[n]++;
    34 }
    35 void multi(int d)        //只是算出后20位的高精乘 
    36 {
    37     int jinwei = 0;
    38     for(int i = 1; i <= maxn; ++i)     
    39     {
    40         b[i] = b[i] * d + jinwei;
    41         jinwei = b[i] / 10;
    42         b[i] %= 10;
    43     }
    44 }
    45 int main() 
    46 {
    47     scanf("%d%d", &n, &r);
    48     for(int i = n - r + 1; i <= n; ++i) fenjie(i);         //将分子分解质因数 
    49     for(int j = r; j > 1; --j) divide(j);            //不断约分 
    50     b[1] = 1;
    51     for (int i = 2; i <= 29999; ++i)        //在a[]里剩的就是得数的所有质因子了,所以只要都乘起来就行了 
    52     {                                        //高精乘 
    53         while (a[i] > 0) 
    54         {
    55             multi(i);
    56             a[i]--;
    57         }
    58     }
    59     for(int i = 10; i >= 1; --i) printf("%d", b[i]);
    60     printf("
    ");
    61     return 0;
    62 }    

    妙,真的妙

  • 相关阅读:
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    查看Linux下端口占用情况的命令
    linux的命令(1)
    xsheell的下载安装初级使用
    日交易,根据权重分配流量的算法,根据权重和交易笔数
    根据权重挑选通道的简单算法
    Java中的String与常量池
    JAVA虚拟机内存分配与回收机制
    JVM 内部运行线程介绍
    AspectJ切入点语法详解
  • 原文地址:https://www.cnblogs.com/mrclr/p/8536930.html
走看看 - 开发者的网上家园