ACM算法(欧拉降幂)

在进行欧拉降幂之前,需要先了解下欧拉函数

欧拉函数

介绍

对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目,即φ(n)。
例如 φ(1)= 1(1与1本身互质)
φ(8)= 4(1, 3, 5, 7 与 8 互质)
并有以下引理,对于素数p
① φ§ = p - 1;
② φ(i * p) = p * φ(i) (i mod p == 0);
③ φ(i * p) = (p - 1) * φ(i) (i mod p != 0);

怎么求

我们可以用欧拉筛素数的方法,根据以上的引理,可以将欧拉函数筛出来。

int m[n],phi[n],p[n],nump;
//m[i]标记i是否为素数,0为素数,1不为素数;p是存放素数的数组;nump是当前素数个数;phi[i]为欧拉函数
int main()
{
        phi[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (!m[i])//i为素数
        {
            p[++nump]=i;//将i加入素数数组p中
            phi[i]=i-1;//因为i是素数,由特性得知    
        }    
        for (int j=1;j<=nump&&p[j]*i<=n;j++)  //用当前已得到的素数数组p筛,筛去p[j]*i
        {
            m[p[j]*i]=1;//可以确定i*p[j]不是素数 
            if (i%p[j]==0) //看p[j]是否是i的约数,因为素数p[j],等于判断i和p[j]是否互质 
            {
                phi[p[j]*i]=phi[i]*p[j]; //特性2
                break;
            }
            else phi[p[j]*i]=phi[i]*(p[j]-1); //互质,特性3其,p[j]-1就是phi[p[j]]   
        }
    }
}

在了解了欧拉函数后,欧拉定理将会很好懂。

公式:当a,n互质时

a^φ(n) ≡ 1 (mod n), 也就是 a^φ(n) % n == 1

那么也就能得到

a^b≡ a^(b*φ(n)) (mod n)

扩展欧拉定理

如果上面的式子中a,n不互质

a^b≡ a^(bφ(n)) (mod n) b < φ(n)
a^b≡ a^(b
φ(n)+φ(n)) (mod n) b >= φ(n)

降幂

将以上的公式结合起来:
a^b≡ a^(b*φ(n)) (mod n) a,n互质
a^b≡ a^b (mod n) b < φ(n)
a^b≡ a^(φ(n)*b+φ(n)) (mod n) b >= φ(n)

那么,现在若对于问题,求a^b%n,则可以根据条件,条件选择相应的公式了?

例题:洛谷P4139

#include<bits/stdc++.h>
#define ll long long
#define N 10000050
#define M 10000000
using namespace std;
const int Inf = 1e9;
int T, tot;
int phi[N], pri[N];
void Prepare_Phi() ///欧拉筛求欧拉函数
{
    phi[1] = 1;
    for(int i = 2; i <= M; ++i)
    {
        if(!phi[i])
            pri[++tot] = i, phi[i] = i-1;///公式1
        for(int j = 1; j <= tot; ++j)
        {
            if(i*pri[j] > M)
                break;
            if(!(i%pri[j]))
            {
                phi[i*pri[j]] = phi[i] * pri[j];///公式2
                break;
            }
            else
                phi[i*pri[j]] = phi[i] * (pri[j]-1);///公式3
        }
    }
}
ll qpow(ll x,ll y,ll mod) ///取余快速幂
{
    ll ret=1;
    while(y)
    {
        if(y&1)
            ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}
ll Solve(ll mod) ///对指数递归,模数因为是取欧拉函数所以递减
{
    if(mod == 1)
        return 0;
    return qpow(2,Solve(phi[mod])+phi[mod],mod);
}
int main()
{
    Prepare_Phi();
    scanf("%d", &T);
    while(T--)
    {
        int p;
        scanf("%d", &p);
        printf("%lld\n",Solve(p));
    }
    return 0;
}
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值