胖爷XP的hu测 T2.电池(数论+扩展欧拉定理)

版权属于XP,想要引用此题(包括题面)的朋友请联系博主

这里写图片描述
这里写图片描述
这里写图片描述

分析:

首先看30%
我们知道根据欧拉定理: aϕ(p)1 a ϕ ( p ) ≡ 1 (mod p) ( a,p a , p 互质)
当p是奇数的时候(一定互质),我们就可以将2的指数部分直接mod ϕ(p) ϕ ( p )

222...=2(22...)modϕ(p) 2 2 2 . . . = 2 ( 2 2 . . . ) m o d ϕ ( p )

同理指数部分的指数也可以mod ϕ(ϕ(p)) ϕ ( ϕ ( p ) )

222...=2(22...)modϕ(p)=2[2(2...)modϕ(ϕ(p))]modϕ(p) 2 2 2 . . . = 2 ( 2 2 . . . ) m o d ϕ ( p ) = 2 [ 2 ( 2 . . . ) m o d ϕ ( ϕ ( p ) ) ] m o d ϕ ( p )

但是当p是偶数的时候,不能直接使用欧拉定理了,怎么破?
没关系,我们让模数 p=2kq p = 2 k q ,其中 q q 是奇数,原式即为:

222...k   (mod q)

这样就可以使用欧拉定理了
使用快速幂,时间复杂度 O(qnlongn) O ( q n l o n g n )

然而,由于 ϕ(ϕ(p))<p2 ϕ ( ϕ ( p ) ) < p 2 ,所以 ϕ(p) ϕ ( p ) O(logn) O ( l o g n ) 次嵌套后就会变成1,等到 phi(p)=1 p h i ( p ) = 1 ,再往上就没有必要了(mod 1=0)

ϕ(ϕ(p))<p2 ϕ ( ϕ ( p ) ) < p 2
  • 如果p为奇数,那么 ϕ(p) ϕ ( p ) 最坏情况等于 p1 p − 1 (质数),那么 phi(p) p h i ( p ) 一定是一个偶数
    偶数的 ϕ ϕ 至多是 12 1 2 (偶数不会与偶数互质),因此 ϕ(ϕ(p))<p2 ϕ ( ϕ ( p ) ) < p 2
  • 如果p为偶数,偶数的 ϕ ϕ 至多是 12 1 2 ,因此 ϕ(ϕ(p))<p2 ϕ ( ϕ ( p ) ) < p 2

可以看到上面做法的复杂度已经完全可以通过100%的数据
但是现在的限制还是在于底数和模数不互质的问题,没法用欧拉定理

那么我们就需要欧拉定理的扩展包了
这里写图片描述

实际上 gcd(a,b)=1 g c d ( a , b ) = 1 gcd(a,b)!=1,b>=ϕ(p) g c d ( a , b ) ! = 1 , b >= ϕ ( p ) 的情况可以合成一个
这里写图片描述

tip

mmp,写多了线筛,结果暴力求phi竟然懵了。。。

一开始看题解还是有一点一知半解,看了代码才明白(总结如下)

  • 嵌套指数的模数一定是嵌套的 ϕ(p) ϕ ( p )
  • 扩展欧拉定理只影响取模方式,并不影响模数
    计算当前指数的时候(快速幂实际上是计算a[l]的指数的),取模方式由和当前模数的关系决定
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long

using namespace std;

const int N=100010;
int n,m,cnt=0;
ll p,pp,a[N],mod[N],f[N];

ll MOD(ll a,ll b) {
    if (a<b) return a;
    else return a%b+b;
}

ll KSM(ll a,ll b,ll mod) {
    ll t=1;
    while (b) {
        if (b&1) t=MOD(t*a,mod);
        b>>=1;
        a=MOD(a*a,mod);
    }
    return t;
}

ll phi(ll a) {
    ll b=a;
    for (int i=2;i*i<=a;i++)
        if (a%i==0) {
            b=b/i*(i-1);
            while (a%i==0) a/=i; 
        }
    if (a!=1) b=b/a*(a-1);
    return b;
}

ll solve(int l,int r,int dep) {
    if (l>r||dep>=cnt) return 1;
    ll pp=solve(l+1,r,dep+1);     //指数
    ll ans=KSM(a[l],pp,f[dep]);   //(a[l]^pp)%f[dep]  
    return ans;        
}

int main() 
{
    scanf("%d%lld",&n,&p); 

    f[++cnt]=p;                                    //phi(phi(p))最多嵌套层数 
    while (f[cnt]!=1) f[++cnt]=phi(f[cnt-1]);

    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    scanf("%d",&m);
    int l,r;
    for (int i=1;i<=m;i++) {
        scanf("%d%d",&l,&r);
        printf("%lld\n",solve(l,r,1)%p);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值