【CodeForces】906 D. Power Tower Extended Euler's Theorem

【Title】D. Power Tower

[Question meaning] Given a sequence of positive integers of length n and a modulus m, ask q times the answer to the cumulative power %m of the interval [l,r]. n,q<=10^5, m,ai<=10^9.

[Algorithm] Extended Euler's Theorem

[Solution] The extended form of Euler's theorem:

$$a^b\equiv a^{b\%\varphi(p)+\varphi(p)} \ \ mod \ \ p \ \ (b\leq \varphi(p))$$

Pay special attention to the invariance when b<φ(p) and (a,p)≠1 .

If it is now three cumulative powers a^(b^c), then according to the extended Euler's theorem:

$$a^{b^c}\ \ mod \ \ p\equiv a^{b^c\%\varphi(p)+\varphi(p)} \ \ mod \ \ p$$

So we only need to calculate:

$$b^c\ \ mod \ \ \varphi(p)$$

When there are more accumulative powers, it is only necessary to recursively take φ until 1 (φ(1)=1). It can be shown that the answer can be obtained at most log(p) times.

The complexity of calculating the cumulative power in this way is O(log p*log n), which is the limit complexity of one query.

The Euler functions used in this process are at most log p, which can be solved directly and violently. The preprocessing complexity is O(log p*√n), which is stored in map and can be directly memorized during implementation.

The total complexity is O(q*log p*log n).

#include<cstdio>
#include<map>
#define ll long long
bool isdigit(char c){return c>='0'&&c<='9';}
int read(){
    int s=0,t=1;char c;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
using namespace std;
const int maxn=100010;
map<int,int>p;
int a[maxn],n,m,q;
int phi(int n){
    if(p.count(n))return p[n];
    int ans=n,m=n;
    for(int i=2;i*i<=n;i++)if(n!=1&&n%i==0){
        ans=ans/i*(i-1);
        while(n%i==0)n/=i;
    }
    if (n> 1 )ans=ans/n*(n- 1 );
    p[m]=ans;
    return ans;
}
int mod(ll x,int y){return x<y?x:x%y+y;}//focus on add,because 2e9*2>int
int power(int x,int k,int m){
    int ans=1;
    while(k){
        if(k&1)ans=mod(1ll*ans*x,m);
        x=mod(1ll*x*x,m);
        k>>=1;
    }
    return ans;
}
int calc(int l,int r,int m){
    if(l==r||m==1)return mod(a[l],m);
    return power(a[l],calc(l+1,r,phi(m)),m);
}    
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    q=read();
    while(q--){
        int l=read(),r=read();
        printf("%d\n",calc(l,r,m)%m);
    }
    return 0;
}        
View Code

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324782904&siteId=291194637