一、题目
二、解法
好像是一个欧拉降幂版题,但仔细想想时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)。
考虑
φ
\varphi
φ的下降速度,有一个结论,当
n
>
2
n>2
n>2时,
φ
(
n
)
\varphi(n)
φ(n)是偶数。
证明可以考虑更相减损术,
gcd
(
i
,
n
)
=
gcd
(
n
−
i
,
n
)
\gcd(i,n)=\gcd(n-i,n)
gcd(i,n)=gcd(n−i,n),所以
i
i
i和
n
−
i
n-i
n−i要么同时互质,要么同时不互质。
由于
φ
(
n
)
=
n
∏
p
i
−
1
p
i
\varphi(n)=n\prod\frac{p_i-1}{p_i}
φ(n)=n∏pipi−1,而
n
n
n又含有一个偶数因子,所以
φ
\varphi
φ的下降是
log
\log
log级的,时间复杂度就有了保证,因为我们在模数为
1
1
1的时候就可以停止迭代。
但是欧拉降幂的写法我们还是需要注意,一定要严格遵循下列公式:
a
c
=
{
a
c
c
<
φ
(
b
)
a
c
%
φ
(
b
)
+
φ
(
b
)
o
t
h
e
r
w
i
s
e
m
o
d
b
a^c=\begin{cases} a^c & c<\varphi(b)\\ a^{c\%\varphi(b)+\varphi(b)} & otherwise \end{cases}\mod b
ac={acac%φ(b)+φ(b)c<φ(b)otherwisemodb
原因是当
gcd
(
a
,
b
)
≠
1
\gcd(a,b)\not =1
gcd(a,b)=1是
a
φ
(
b
)
=
1
m
o
d
b
a^{\varphi(b)}=1 \mod b
aφ(b)=1modb不一定成立,这也是欧拉降幂的一大难点,代码中会写详细的注释。
#include <cstdio>
#include <cmath>
#include <map>
using namespace std;
#define int long long
const int MAXN = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,q,l,r,a[MAXN];
map<int,int> ph;
int phi(int n)//算欧拉函数
{
int t=sqrt(n),res=n;
for(int i=2;i<=t;i++)
{
if(n%i==0)
{
res/=i;res*=(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) res/=n,res*=(n-1);
return res;
}
int qkpow(int a,int b,int MOD)
{
int res=1;
while(b>0)
{
if(b&1) {res=res*a;if(res>=MOD) res=res%MOD+MOD;}
a=a*a;if(a>=MOD) a=a%MOD+MOD;
//这里要注意,如果中途出现了>=MOD的情况我们要加上MOD,以满足欧拉降幂的公式
b>>=1;
}
return res;
}
int dfs(int x,int p)
{
if(x==r+1 || p==1)//出口,p=1时要返回1,因为我们要加上p,也就是上一层的phi[p]
return 1;
int t=dfs(x+1,ph[p]);//默认返回的值是满足公式的,qkpow需要维护
return qkpow(a[x],t,p);
}
signed main()
{
n=read();m=read();
int cur=m;
while(cur!=1) ph[cur]=phi(cur),cur=ph[cur];
ph[cur]=1;//预处理所有可能用到的phi,存map
for(int i=1;i<=n;i++)
a[i]=read();
q=read();
while(q--)
{
l=read();r=read();
printf("%lld\n",dfs(l,m)%m);
}
}