Poj P1845 Sumdiv___乘法逆元+分解质因数

题目大意:

给出 A , B ,求 A B 的约数之和 m o d 9901

1 A , B 5 10 7

分析:

A 进行质因数分解,可得:
p 1 c 1 p 2 c 2 p m c m
则我们可以推出 A B 可表达为:
p 1 B c 1 p 2 B c 2 p m B c m
A B 的约数和可以表示为:
1 + p 1 + p 1 2 + + p 1 B c 1 1 + p 2 + p 2 2 + + p 2 B c 2 1 + p m + p m 2 + + p m B c m
我们设
x为任意一个 1 + p i + p i 2 + + p i B c i
可以发现
x在 p i 的表示为一个长为 B c i + 1 的数且每一位都是 1
那么我们要求的即为
一个在 p i 长为 B c i + 1 的且每一位都是 p i 1
/ p i 1 的数
那么显然这个数为 p i B c i + 1 1
那么显然x 为 p i B c i + 1 1 / p i 1 m o d 9901

那么我们就可以用快速幂去求出 p i B c i + 1
对于 / p i 1
因为 9901 为素数,
所以我们当 ( p i 1 ) 不是 9901 倍数的时候,可以直接计算其的乘法逆元,
而如果为其倍数,那么我们可以发现 p i m o d 9901 = 1
那么我们回到一开始的算式 p i + p i + p i 2 + + p i B c i
显然
p i + p i + p i 2 + + p i B c i = B c i + 1 ( m o d 9901 )

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define modn 9901
#define N 25

using namespace std;

typedef long long LL;

int a, b, num, cnt[N][2];

void divide(int x){
    num = 0;
    for (int i = 2; i * i <= x; i++){
         if (x % i == 0){
             cnt[++num][0] = i;
             while (x % i == 0) x /= i, cnt[num][1]++;
         }
    }
    if (x != 1) cnt[++num][0] = x, cnt[num][1] = 1;     
}

int ksm(int a, LL b){
    int rp = 1;
    for (; b ; b >>= 1){
         if (b & 1) rp =(LL) rp * a % modn;
         a = (LL) a * a % modn;
    }   
    return rp;
}

int main(){
    scanf("%d %d", &a, &b);
    divide(a);
    int ans = 1;
    for (int i = 1; i <= num; i++)
         if ((cnt[i][0] - 1) % modn == 0)
              ans = ((LL)b * cnt[i][1] + 1) % modn * ans % modn;
         else {
              int x = ksm(cnt[i][0], (LL)cnt[i][1] * b + 1);
              x = (x - 1 + modn) % modn;  
              int y = ksm(cnt[i][0] - 1, modn - 2);
              ans = (LL)ans * x % modn * y %modn;
         }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/gx_man_vip/article/details/80292871