数论--阶乘幂&扩展欧拉定理--codeforces 906d Power Tower

这篇博客介绍了如何利用扩展欧拉定理解决数论问题,特别是针对给定数组的指数运算查询。通过快速幂算法和递归方法,有效地计算了数组元素之间的幂运算并取模的结果。同时,文章提供了一个名为`qk_pow`的快速幂函数实现,以及一个`f`函数来处理查询过程中的递归计算。
摘要由CSDN通过智能技术生成

给定数组w,q次查询,求w[ql]^ ( w[ql + 1] ^ ( ... w[qr - 1] ^ (w[qr]) ) ) % m

扩展欧拉定理 (a,m) != 1时,

if(b >= phi(m)) a^b % m = a ^ (b % phi(m) + phi(m) ) % m

if(b < phi(m)) a^b % m = a ^ b % m(快速幂)

1.快速幂和递归时要时刻注意指数和phi(m)的大小关系

ll qk_pow(ll a,ll b,ll p)

{

    ll ans = 1;

     a = a >= p ? a % p + p : a;

    while (b) {

        if(b & 1) ans = ans * a >= p ? ans * a % p + p : ans * a % p;

        b >>= 1;

        a = a * a >= p ? a * a % p + p : a * a % p;

    }

    return ans;

}

2.

ll f(int ql,int qr,int pos)

{

    int m = v[pos];

    if(m == 1) return 1;

    if(ql == qr) return w[ql] < m ? w[ql] : w[ql] % m + m;

    ll x = f(ql + 1,qr,pos + 1);

    ll ans = qk_pow(w[ql], x , m);

    return ans;

}


#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int n,m;
int w[maxn];

vector<int> v;

int phi(int m)
{
    int ans = m;
    for (int i = 2; i <= sqrt(0.5 + m); i ++) {
        if(m % i == 0){
            ans = ans / i * (i - 1);
            while(m % i == 0 ) m /= i;
        }
    }
    if(m > 1) ans = ans / m * (m - 1);
    return ans;
}

void init(int m)
{
    v.clear();
//预处理phi(m)
    int x = m;
    v.push_back(x);
    while (1) {
        x = phi(x);
        v.push_back(x);
        if(x == 1) break;
    }
}
ll qk_pow(ll a,ll b,ll p)
{
    ll ans = 1;
    a = a >= p ? a % p + p : a;
    while (b) {
        if(b & 1) ans = ans * a >= p ? ans * a % p + p : ans * a % p;
        b >>= 1;
        a = a * a >= p ? a * a % p + p : a * a % p;
    }
    return ans;
}

ll f(int ql,int qr,int pos)
{
    int m = v[pos];
    if(m == 1) return 1;
    if(ql == qr) return w[ql] < m ? w[ql] : w[ql] % m + m;
    ll x = f(ql + 1,qr,pos + 1);
    ll ans = qk_pow(w[ql], x , m);
    return ans;
}
int main()
{
   
    while (scanf("%d%d",&n,&m) != EOF) {
         init(m);
        for (int i = 1; i <= n; i ++) {
            scanf("%d",&w[i]);
        }
        int q;scanf("%d",&q);
        int ql,qr;
        ll ans;
        while (q --) {
            scanf("%d%d",&ql,&qr);
             ans = f(ql,qr,0);
            ans = (ans + m) % m;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值