题意:
给定一个长度为n的数组w,模数m,
q组询问,每组询问给定l,r,要求计算:
数据范围:n,q<=1e5,m<=1e9,w(i)<=1e9
解法:
递归处理,虽然要求计算[L,R],但是模数phi[p]会不断变小,O(log)层就会变为1
因为m是1e9的,只能O(sqrt)计算phi,
但是因为只有O(log)层,也只需要记录O(log)个phi,开个map记录一下phi,避免每次计算phi都要O(sqrt)
降幂公式:
当不保证互质的时候,降幂过程需要比较b和phi[p]的大小然后分情况,但是b很大,不好比较,
可以将取模替换为:
int mo(long long x,int mod) {return x<mod?x:x%mod+mod;}
这是在比较b和phi[p]的大小,如果b<phi[p],返回b;否则返回b%phi[p]+phi[p]。
(其他地方看到的一个说法:保留一个phi[p]是为了保证取模之后仍然满足欧拉降幂的公式,防止把原本大于phi[p]的数取模之后变为小于phi[p])
将solve函数和快速幂函数中的取模都替换成这个,这样就不用分类讨论了
最后得到的答案需要加一个正常的%mod
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=1e5+5;
int a[maxm];
int n,m;
int mo(ll x,int mod){
return x<mod?x:x%mod+mod;
}
int phi(int n){//单个数的欧拉函数值
static unordered_map<int,int>p_mark;//开个map存,避免每次查询复杂度都是O(sqrt(n))
if(p_mark.count(n))return p_mark[n];//如果map中有则直接返回
int nn=n;
int ans=n;
for(int i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0)n/=i;
}
}
if(n>1)ans=ans/n*(n-1);
return p_mark[nn]=ans;//记录到map中
}
int ppow(int a,int b,int mod){
int ans=mo(1,mod);a=mo(a,mod);
while(b){
if(b&1)ans=mo(1LL*ans*a,mod);
a=mo(1LL*a*a,mod);
b>>=1;
}
return ans;
}
int solve(int l,int r,int m){
if(m==1)return mo(a[l],m);
if(l==r)return mo(a[l],m);
return ppow(a[l],solve(l+1,r,phi(m)),m);
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int q;scanf("%d",&q);
while(q--){
int l,r;scanf("%d%d",&l,&r);
int ans=solve(l,r,m)%m;
printf("%d\n",ans);
}
return 0;
}