费马小定理求逆元+约数的和+等比数列求和+取模

Sumdiv
求A^B的所有约数的和。
将A分解 A = i = 1 m p i c i A=\prod_{i=1}^m p_i^{c_i}

i = 1 m k = 0 c i p i k = ( 1 + p 1 1 + p 1 B c 1 ) ( ( 1 + p m 1 + p 1 B c m \prod_{i=1}^m (\sum_{k=0}^{c_i} p_i^{k})=(1+p_1^{1}+……p_1^{B*c_1})*……*((1+p_m^{1}+……p_1^{B*c_m})

等比数列求和 p i B c i + 1 1 p i 1 \frac{p_i^{B*c_i+1}-1}{p_i-1}
分类讨论:
①p1-1是9901的倍数,直接对原始式子取模。
②p1-1与9901互质,除法取模求逆元。
用费马小定理得出 p i 1 p_i-1 关于模数的逆元。
快速幂求出。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int p = 9901;
struct node{
    int p,ci;
}a[100];
int j;
void fenjie(int n){
    j=0;
    int k=sqrt(n+1);
    for(int i=2;i<=k;i++){
        if(n%i==0){
            a[++j].p=i;
            while(n%i==0){
                a[j].ci++;n/=i;
            }
        }
    }
    //防止 n 自己就是素数
    if(n>k){
        a[++j].p=n;a[j].ci=1;
    }
}

ll pow(ll a,ll n,ll p){
    ll ans=1;
    while(n){
        if(n&1) ans=ans*a%p;  //如果无需取模,去掉 %p即可
        a=a*a%p;  // 是 平方
        n/=2;
    }
    return ans%p;
}

int main(){
    int A,B;
    cin>>A>>B;
    if(A==0)
    {
        printf("%d\n",0);
        return 0;
    }
    else if(B==0){
        printf("%d\n",1);
        return 0;
    }
    fenjie(A);
    ll ans=1;
    for(int i=1;i<=j;i++)
    {
        if((a[i].p-1)%p==0)
        {
            ans =(ll)(1+B*a[i].ci)%p*ans%p;
        }
        else
        {
            ans = (pow(a[i].p, B*a[i].ci+1,p)-1+p)%p*pow(a[i].p-1, p-2,p)%p*ans%p;
        }
    }
    printf("%lld\n",ans%p);
    return 0;
}
发布了67 篇原创文章 · 获赞 0 · 访问量 1515

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/104524407
今日推荐