学习笔记#欧拉定理#龟速乘

引入

一个问题:求a的b次方对m取模的结果

思考1

好像很简单,快速幂就可以了
如果b是10的20000000次方呢
emmmmm这是不可做题吧
一定要把b缩小,怎么缩小呢

欧拉定理

φ(n)表示小于等于n的正整数中与n互质的数的个数(欧拉函数)。
a与m互质时,a^φ(m)%m=1
https://s2.ax1x.com/2019/04/15/AjPMlQ.md.jpg

扩展欧拉定理

该定理不需要a与m互质
b>=φ(m)时,a^b%m=a^(b%φ(m)+φ(m))%m
https://s2.ax1x.com/2019/04/15/AjPlOs.md.jpg

思考2

这样就可以缩小b了,但是如果m是10的12次方呢,好像取模之前就会爆long long了
难道要写高精度?高精度也要超时啊QwQ,怎么办

龟速乘

这是什么玩意,好吧,它可以让我们解决乘起来爆long long的问题
它是怎么实现的呢,用加法代替乘法,和快速幂相似的是,快速幂每次会以平方的倍数增大,而龟速乘是翻倍增大

ac代码

来放一下具体的代码吧

#include<bits/stdc++.h>
using namespace std;
long long phi(long long n)
{
    long long res=n;
    for(long long i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            res-=res/i;
            while(n%i==0)n/=i;
        }
    }
    if(n>1)res-=res/n;
    return res;
}
//欧拉函数
long long mul(long long x,long long y,long long mod)
{
    long long ans=0;
    while(y!=0)
    {
        if(y%2)ans+=x,ans%=mod;
        x=x+x,x%=mod,y>>=1; 
    }
    return ans;
}
//加法代替乘法
long long pow(long long x,long long y,long long mod)
{
    long long ans=1;
    while(y!=0)
    {
        if(y%2)ans=mul(ans,x,mod);
        x=mul(x,x,mod),y>>=1;
    }
    return ans;
}
//龟速乘
long long a,b,m,x,ans=1,flg=0;
char c;
int main()
{
    scanf("%lld%lld",&a,&m),x=phi(m);
    while(!isdigit(c=getchar()));
    for(;isdigit(c);c=getchar())
    {
        b=b*10+c-'0';
        if(b>=x)b%=x,flg=1;
    }
    if(flg)b+=x;
    //以上是使用拓展欧拉定理来缩小b
    printf("%lld",pow(a,b,m));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值