zoukankan      html  css  js  c++  java
  • Mathematics:X-factor Chains(POJ 3421)

                  

                   X链条

      题目大意,从1到N,1 = X0X1X2, …, Xm = X中间可以分成很多数,另Xi < Xi+1 Xi 可以整除Xi+1 ,求最大长度m和m长度的链有多少条

      思路:

      很简单,只要把数分解质因数就可以了,最后链条的长度为质因数的个数,组合数为质因数个数的阶乘除以各自重复质因数的阶乘。还记得我发过的GCM和LCM反转的那道题吗,可以用pallord_rho算法分解质因数。

      贴代码,第一个是最坑爹的,这一题会专门出数据坑Miller_Rabin算法,所以必须素数验证必须执行8次以上,不能用srand改变种子,否则你就是在和上帝玩骰子。

      

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <functional>
      4 #include <time.h>
      5 
      6 using namespace std;
      7 typedef long long LL_INT;
      8 
      9 bool Miller_Rabin(const LL_INT);
     10 LL_INT witness(const LL_INT,const LL_INT,const LL_INT);
     11 void Find_Factors(const LL_INT, int *const, const int);
     12 LL_INT Pallord_Rho_Theorem(const LL_INT, const int);
     13 LL_INT Multi_Function(LL_INT,const LL_INT);
     14 LL_INT gcd(LL_INT, LL_INT);
     15 
     16 static LL_INT factors[10000], factors_num[10000]; 
     17 static long long coe[23];
     18 static int factors_sum[10000];
     19 
     20 void Inivilize(void)
     21 {
     22     coe[1] = 1;
     23     for (int i = 2; i <= 20; i++)
     24         coe[i] = coe[i - 1] * i;
     25 }
     26 
     27 int main(void)
     28 {
     29     LL_INT x;
     30     long long chains_sum;
     31     int prime_sum, len, i;
     32 
     33     Inivilize();
     34     while (~scanf("%lld", &x))
     35     {
     36         prime_sum = 0; len = 0;
     37         if (x <= 1)
     38             printf("0 1
    ");
     39         else if (Miller_Rabin(x))//如果是素数,直接返回1 1
     40             printf("1 1
    ");
     41         else
     42         {
     43             Find_Factors(x, &prime_sum, 120);//120是经验值
     44             sort(factors, factors + prime_sum);
     45             factors_num[0] = factors[0]; 
     46             memset(factors_sum, 0, sizeof(factors_sum));
     47             factors_sum[0] = 1;
     48             for (i = 1; i < prime_sum; i++)
     49             {
     50                 if (factors[i - 1] == factors[i])
     51                     factors_sum[len]++;
     52                 else
     53                 {
     54                     factors_num[++len] = factors[i];
     55                     factors_sum[len] = 1;
     56                 }
     57             }
     58             chains_sum = coe[prime_sum];
     59             for (int i = 0; i <= len; i++)
     60                 chains_sum /= coe[factors_sum[i]];
     61             printf("%d %lld
    ", prime_sum, chains_sum);
     62         }
     63     }
     64     return 0;
     65 }
     66 
     67 bool Miller_Rabin(const LL_INT n)
     68 {
     69     if (n == 2)
     70         return true;//如果是2,就不用判断了
     71     else
     72     {
     73         for (int i = 0; i < 8; i++)
     74         {
     75             if (!(witness((LL_INT)(rand() % (n - 1)) + 1, n - 1, n) == 1))
     76                 return false;
     77         }
     78         return true;
     79     }
     80 }
     81 
     82 LL_INT witness(const LL_INT coe, const LL_INT level, const LL_INT n)
     83 {
     84     LL_INT y, x;
     85     if (level == 0)
     86         return 1;
     87     x = witness(coe, level >> 1, n);
     88 
     89     if (x == 0)
     90         return 0;
     91     y = (x*x) % n;
     92     if (y == 1 && x != 1 && x != n - 1)
     93         return 0;//费马小定理的运用
     94     if (level % 2 == 1)
     95         y = (coe*y) % n;
     96 
     97     return y;
     98 }
     99 
    100 void Find_Factors(const LL_INT n, int *const len, const int times)
    101 {
    102     if (n == 1)
    103         return;
    104     else if (Miller_Rabin(n))
    105         factors[(*len)++] = n;
    106     else
    107     {
    108         LL_INT p = n;
    109         int c = times;
    110         while (p >= n)
    111             p = Pallord_Rho_Theorem(n, c--);
    112         Find_Factors(p, len, times);
    113         Find_Factors(n / p, len, times);
    114     }
    115 }
    116 
    117 LL_INT Pallord_Rho_Theorem(const LL_INT n, const int c)
    118 {
    119     LL_INT x, y, k = 2, d;
    120     x = y = rand() % n;//随意取一个随机数
    121 
    122     for (int i = 1;; i++)
    123     {
    124         x = (Multi_Function(x, n) + c) % n;
    125         d = gcd(n, (y - x + n) % n);//计算|y-x|与n的最大公因数
    126         if (1 < d && d < n)
    127             return d;
    128         else if (y == x)
    129             return n;//相当于这个因数分解是失败的,所以直接返回n让外层循环继续
    130         else if (i == k)//brent判据,目的就是找到在偶数周期内找到gcd(x(k)-x(i/2))
    131         {
    132             y = x;//重新y=x,定义循环
    133             k <<= 1;
    134         }
    135     }
    136     return n;
    137 }
    138 
    139 LL_INT Multi_Function(LL_INT x,const LL_INT mod)
    140 {
    141     LL_INT y = x, ans = 0;
    142     while (y)//计算y=x^2的取模算法
    143     {
    144         if (y & 1)
    145             ans = (ans + x) % mod;
    146         x = (x << 1) % mod;
    147         y >>= 1;
    148     }
    149     return ans;
    150 }
    151 
    152 LL_INT gcd(LL_INT a, LL_INT b)
    153 {
    154     if (b == 0)
    155         return a;
    156     return gcd(b, a%b);
    157 }

    挺慢的,其实直接用筛法更快,先把表打好,然后再一个一个选就可以了,用筛法的话可以到100ms以内

     1 #include <iostream>
     2 #include <functional>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 
     7 static bool primes[(1 << 20) + 5];
     8 static int primes_set[500000];
     9 static long long fact[22];
    10 
    11 void Inivilize(int *const primes_sum)
    12 {
    13     int i, j;
    14     primes[1] = primes[0] = 1;
    15     for (i = 2; i <= 1 << 20; i++)
    16     {
    17         if (!primes[i]) primes_set[(*primes_sum)++] = i;
    18         for (j = 2; j*i <= 1 << 20 && j <= i; j++)
    19         {
    20             if (primes[j] == 0)
    21                 primes[j*i] = 1;
    22         }
    23     }
    24     fact[1] = 1;
    25     for (i = 2; i <= 21; i++)
    26         fact[i] = fact[i - 1] * i;
    27 }
    28 
    29 int main(void)
    30 {
    31     int x, last, i, tmp_div_sum, tmp_last, longest_length, primes_sum = 0, prime_num;
    32     long long div_sum, chain_sum;
    33     Inivilize(&primes_sum);
    34 
    35     while (~scanf("%d", &x))
    36     {
    37         if (x == 1)
    38             printf("0 1
    ");
    39         else
    40         {
    41             div_sum = 1; last = x; longest_length = 0; 
    42             for (i = 0; last != 1; i++)
    43             {
    44                 if (!primes[last])
    45                 {
    46                     longest_length++;
    47                     break;
    48                 }
    49                 prime_num = primes_set[i];
    50                 for (tmp_div_sum = 0, tmp_last = last; tmp_last%prime_num == 0;)
    51                 {
    52                     if (!tmp_last) break;
    53                     tmp_last /= prime_num;
    54                     tmp_div_sum++; longest_length++;
    55                 }
    56                 last = tmp_last;
    57                 if (tmp_div_sum)
    58                     div_sum *= fact[tmp_div_sum];
    59             }
    60             chain_sum = fact[longest_length];
    61             chain_sum /= div_sum;
    62             printf("%d %lld
    ", longest_length, chain_sum);
    63         }
    64     }
    65     return 0;
    66 }

  • 相关阅读:
    Centos7:mariadb替换mysql
    CentOS5 部署 戴尔OMSA
    《Zero MQ》
    可扩展的Web架构和分布式系统
    队列实现
    超级好用的正则表达式网站
    <转>undefined与null的区别
    JS事件
    sublime text 3 快捷键
    设置className的方式(不使用setAttribute)
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5010929.html
Copyright © 2011-2022 走看看