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

给定数组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;
}

猜你喜欢

转载自blog.csdn.net/SM_545/article/details/81141794
今日推荐