zoukankan      html  css  js  c++  java
  • hdu1845(a^b的因子和%p)

    题目链接:http://poj.org/problem?id=1845

    思路:

    1.整数唯一分解定理:

          任意正整数都有且只有一种方式写出其素因子的乘积表达式。

          a=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数

    2.约数和公式:

      对于已经分解的整数a=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)

      有a的所有因子之和为

         S` = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)

    那么 a^b 的所有因子和为

      S = (1+p1+p1^2+p1^3+...p1^(k1*b)) * (1+p2+p2^2+p2^3+….p2^(k2*b)) * (1+p3+ p3^3+…+ p3^(k3*b)) * .... * (1+pn+pn^2+pn^3+...pn^(kn*b))

    对于数列 1, p, p^2, p^3 ...  p^n % mod,其中  mod 为质数,打个表可以发现该数列是一个循环数列,其中存在一个循环节为 1, p, p^1, ... p^(mod-2).其实这点在费马小定理中是有体现的,a^(mod-1) = 1 (% mod).

    那么对于求 cnt = 1 + p + p^2 + ... + p^n % mod,可以令

      cc1 = (n + 1) / (mod - 1)

      cc2 = (n + 1) % (mod - 1)

      cnt1 = 1 + p + p^2 + ... + p^(mod - 2)

      cnt2 = 1 + p + p^2 + ... + p^(cc2 - 1)

    那么 cnt = cc1 * cnt1 + cnt2 % mod

    对于求 a^b,可以先将 a 质因分解,得到 S 的表达式,对于 S 表达式,只需要按照上面的方法求出其中每个乘数项即可.时间复杂度为 O(loga * mod), 本题中 mod = 9901, 时间上是允许的.

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <map>
     4 #define ll long long
     5 using namespace std;
     6 
     7 const int mod = 9901;
     8 const int MAXN = 1e5 + 10;
     9 ll prime[MAXN], indx = 0;
    10 map<int, int> num;
    11 
    12 int get(ll a, ll b){//计算sigma(a^i),其中0<=i<=b
    13     ll sol1 = 0, sol2 = -1, cnt = 1;
    14     ll cc1 = (b + 1) / (mod - 1);
    15     ll cc2 = (b + 1) % (mod - 1);
    16     for(int i = 0; i < mod - 1; i++){
    17         sol1 = (sol1 + cnt) % mod;
    18         if(sol2 == -1 && i + 1 == cc2) sol2 = sol1;
    19         cnt = (cnt * a) % mod;
    20     }
    21     return (sol1 * cc1 % mod + sol2) % mod;
    22 }
    23 
    24 int main(void){
    25     ll a, b, sol = 1;
    26     cin >> a >> b;
    27     for(int i = 2; i * i <= a; i++){
    28         if(a % i == 0){
    29             prime[indx] = i;
    30             while(a % i == 0){
    31                 num[i]++;
    32                 a /= i;
    33             }
    34             indx++;
    35         }
    36     }
    37     if(a > 1) prime[indx++] = a, num[a]++;
    38     for(int i = 0; i < indx; i++){
    39         sol = (sol * get(prime[i], b * num[prime[i]])) % mod;
    40     }
    41     cout << sol << endl;
    42     return 0;
    43 }
    View Code

    但是当 mod 比较大时这个方法就不行了,mod 比较大时可以用下面这个代码,贴的 Kuangbin 模板

    代码:

     1 #include <stdio.h>
     2 #include <math.h>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <string.h>
     6 #define ll long long
     7 using namespace std;
     8 
     9 //******************************************
    10 //素数筛选和合数分解
    11 const int MOD = 9901;
    12 const int MAXN=10000;
    13 int prime[MAXN+1];
    14 
    15 void getPrime(void){
    16     memset(prime, 0, sizeof(prime));
    17     for(int i = 2; i <= MAXN; i++)
    18     {
    19         if(!prime[i]) prime[++prime[0]] = i;
    20         for(int j=1; j<= prime[0]&&prime[j] <= MAXN/i; j++)
    21         {
    22             prime[prime[j]*i] = 1;
    23             if(i % prime[j] == 0) break;
    24         }
    25     }
    26 }
    27 
    28 ll factor[100][2];
    29 int fatCnt;
    30 
    31 int getFactors(ll x){
    32     fatCnt = 0;
    33     ll tmp = x;
    34     for(int i=1; prime[i] <= tmp/prime[i]; i++){
    35         factor[fatCnt][1] = 0;
    36         if(tmp % prime[i] == 0){
    37             factor[fatCnt][0] = prime[i];
    38             while(tmp % prime[i] == 0){
    39                 factor[fatCnt][1]++;
    40                 tmp /= prime[i];
    41             }
    42             fatCnt++;
    43         }
    44     }
    45     if(tmp!=1)
    46     {
    47         factor[fatCnt][0]=tmp;
    48         factor[fatCnt++][1]=1;
    49     }
    50     return fatCnt;
    51 }
    52 
    53 //******************************************
    54 ll pow_m(ll a, ll n)//快速模幂运算
    55 {
    56     ll res = 1;
    57     ll tmp = a % MOD;
    58     while(n){
    59         if(n & 1){ 
    60             res *= tmp;
    61             res%=MOD;
    62         }
    63         n >>= 1;
    64         tmp *= tmp;
    65         tmp %= MOD;
    66     }
    67     return res;
    68 }
    69 
    70 ll sum(ll p, ll n){//计算1+p+p^2+...+p^n
    71     if(p == 0)return 0;
    72     if(n == 0)return 1;
    73     if(n & 1){//奇数
    74         return ((1 + pow_m(p, n/2 + 1)) % MOD * sum(p, n / 2) % MOD) % MOD;
    75     }else return ((1 + pow_m(p, n / 2 + 1)) % MOD * sum(p, n / 2 - 1) + pow_m(p, n / 2) % MOD) % MOD;
    76 
    77 }
    78 
    79 int main(void){
    80     int A, B;
    81     getPrime();
    82     while(scanf("%d%d", &A, &B) != EOF){
    83         getFactors(A);
    84         ll ans = 1;
    85         for(int i = 0; i < fatCnt; i++){
    86             ans *= (sum(factor[i][0], B * factor[i][1]) % MOD);
    87             ans %= MOD;
    88         }
    89         printf("%lld
    ",ans);
    90     }
    91     return 0;
    92 }
    View Code
  • 相关阅读:
    [CF1439B] Graph Subset Problem
    [CF1439C] Greedy Shopping
    [CF1119F] Niyaz and Small Degrees
    [ARC101C] Ribbons On the Tree
    [CF1446C] Xor Tree
    11月24日 模拟赛 题解
    UOJ346
    [CF1229C] Konrad and Company Evaluation
    [CF1326F] Wise Men (Hard Version)
    学军联赛模拟 第二十七测 题解
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7609041.html
Copyright © 2011-2022 走看看