约数,快速幂和扩展欧几里得算法

快速幂

快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

  • 原理
    一个数b ( b > 0 ) 一定可以表示为若干指数不重复的2的次幂的和
    (k为b在二进制下表示的位数个数)
    b = C k − 1 2 k − 1 + C k − 2 2 k − 2 + . . . + C 0 2 0 b=C_{k-1}2^{k-1}+C_{k-2}2^{k-2}+...+C_{0}2^{0} b=Ck12k1+Ck22k2+...+C020
    于是ab可以表示为
    a b = a C k − 1 2 k − 1 × a C k − 1 2 k − 1 × . . . × a C 0 2 0 a^{b}=a^{C_{k-1}2^{k-1}} \times a^{C_{k-1}2^{k-1}}\times...\times a^{C_{0}2^{0}} ab=aCk12k1×aCk12k1×...×aC020

    公式 r e s = ∏ i = 0 k − 1 a C i 2 i res=\prod_{i=0}^{k-1}a^{C_{i}2^{i}} res=i=0k1aCi2i
    快速幂模板(求ab

#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
    int  a,b,p,res=1;
    cin>>a>>b>>p;
    for(;b;b>>=1)
    {
        if(b&1) res=(ll)res*a%p; //防止爆int,开long long
        a=(ll)a*a%p;
    }
    cout<<res%p; //防止p=1,b=0时,所以再mod p
}

约数

这里主要讲一下一个数的约数之和约数个数

根据算术基本定理,正整数N可以被唯一分解为质数的次幂的乘积的形式
N = p 1 c 1 p 2 c 2 . . . p m c m ( p 为 质 数 ) N=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}} (p为质数) N=p1c1p2c2...pmcm(p)

所以N的约数个数

( c 1 + 1 ) × ( c 2 + 1 ) × . . . × ( c m + 1 ) = ∏ i = 1 m ( c i + 1 ) (c_{1}+1)\times(c_{2}+1)\times...\times(c_{m}+1)=\prod_{i=1}^{m}(c_{i}+1) (c1+1)×(c2+1)×...×(cm+1)=i=1m(ci+1)

约数之和为

( 1 + p 1 + p 1 2 + . . . + p 1 c 1 ) × . . . × ( 1 + p m + p m 2 + . . . + p m c m ) = ∏ i = 1 m ∑ j = 0 c i p i j (1+p_{1}+p_{1}^{2}+...+p_{1}^{c_{1}})\times...\times(1+p_{m}+p_{m}^{2}+...+p_{m}^{c_{m}})=\prod_{i=1}^{m}\sum_{j=0}^{c_{i}}p_{i}^{j} (1+p1+p12+...+p1c1)×...×(1+pm+pm2+...+pmcm)=i=1mj=0cipij

(希望大家自己推一下,不浪费多少时间)
这里我们就来一道有点难度的题

约数之和
A B A^{B} AB的所有约数之和
在套用公式的时候需要注意的是公式的变形
然后用等比数列求解(用乘法逆元将除法变为乘法,原理为费马小定理)

(思考一下)
代码仅供参考,也有别的解法

#include<iostream>
#include<algorithm>
#include<unordered_map>
#define mod 9901
using namespace std;
typedef long long ll;
unordered_map<int,int>tt;
int a,b;
ll qmi(int a,ll b){ //快速幂
    ll res=1;
    for(;b;b>>=1){
        if(b&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
    }
    return res;
}
int main(){
    cin>>a>>b;
    if(a==0){
        cout<<0;
        return 0;
    }
    for(int i=2;i<=a/i;i++){ //分解质因子
        while(a%i==0){
            a/=i;
            tt[i]++;
        }
    }
    if(a>1) tt[a]++;
    ll res=1;
    for(auto i:tt){
        int x=i.first,y=i.second;
        if((x-1)%mod==0) //没有逆元的情况
            res=((ll)b*y+1)%mod*res%mod;
        else
            res=(ll)res*(qmi(x,(ll)y*b+1)-1)%mod*qmi(x-1,(ll)mod-2)%mod;//等比数列公式
        res=(res+mod)%mod;//防止负数
    }
    cout<<res;
    return 0;
}

扩展欧几里得算法

  • 裴蜀定理

对于任意整数a和b,存在一对整数x和y,满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
换而言之
公式 a x + b y = d ax+by=d ax+by=d 有x和y的解就必须满足 g c d ( a , b ) ∣ d gcd(a,b)\mid d gcd(a,b)d (这个推论非常重要)

结合欧几里得算法就可以解出很多问题了(包括扩展中国剩余定理)
这里给出证明过程(写纸上)
在这里插入图片描述
模板题
线性同余方程

代码如下

#include<iostream>

using namespace std;
int n;
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x); //将x和y掉位置,方便一点
    y-=a/b*x; 
    return d;
}
int main(){
    cin>>n;
    while(n--){
        int a,b,m,x,y;
        scanf("%d%d%d",&a,&b,&m);
        int d=exgcd(a,m,x,y);
        if(b%d) puts("impossible");
        else printf("%d\n",(long long)b/d*x%m);
    }
    return 0;
}

本来还想写一下中国剩余定理和高斯消元的,想想算了,这得写两小时啊,哪来这么多时间

祝大家新年快乐,插上翅膀,犇向远方

以梦为马 不负韶华 0.0

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值