知识点:拓展欧拉定理、记忆化、欧拉函数、快速幂
题意
给定序列
a
i
a_i
ai,
q
q
q次询问
a
[
l
,
r
]
a_{[l,r]}
a[l,r]的数构成以下形式对
m
m
m取模后的结果:
a
l
(
a
l
+
1
(
a
i
+
2
(
.
.
.
a
r
−
1
a
r
)
)
)
a_l^{(a_{l+1}^{(a_{i+2}^{(...^{a_{r-1}^{a_r}})})})}
al(al+1(ai+2(...ar−1ar)))
思路
拓展欧拉定理:
a
c
≡
a
c
%
φ
(
m
)
+
φ
(
m
)
i
f
c
≥
φ
(
m
)
a^c\equiv a^{c\% \varphi(m)+\varphi(m)} \quad if \ c\geq \varphi(m)
ac≡ac%φ(m)+φ(m)if c≥φ(m)
a
c
≡
a
c
i
f
c
<
φ
(
m
)
a^c\equiv a^c \quad if \ c< \varphi(m)
ac≡acif c<φ(m)
(
m
o
d
m
)
(mod \ m)
(mod m)
其中
φ
(
m
)
\varphi(m)
φ(m)为欧拉函数
令所求形式为:
f
(
l
,
r
)
f(l,r)
f(l,r)
递推式:
f
(
l
,
r
)
=
a
l
f
(
l
+
1
,
r
)
f(l,r)=a_l^{f(l+1,r)}
f(l,r)=alf(l+1,r)
取模:
f
(
l
,
r
)
%
m
=
(
a
l
%
m
)
f
(
l
+
1
,
r
)
%
φ
(
m
)
+
φ
(
m
)
%
m
f(l,r)\%m=(a_l\%m)^{f(l+1,r)\%\varphi(m)+\varphi(m)}\%m
f(l,r)%m=(al%m)f(l+1,r)%φ(m)+φ(m)%m(假定
c
≥
φ
(
m
)
c\geq \varphi(m)
c≥φ(m))
观察到递推式中模数由
m
m
m降为
φ
(
m
)
\varphi(m)
φ(m)、再降为
φ
(
φ
(
m
)
)
等
\varphi(\varphi(m))等
φ(φ(m))等,证明
φ
(
m
)
\varphi(m)
φ(m)降为
1
1
1的时间复杂度为
O
(
l
o
g
m
)
O(logm)
O(logm):
m
m
m为偶数:
m
=
2
n
×
p
i
n
i
m=2^n\times p_i^{n_i}
m=2n×pini
φ
(
m
)
=
(
2
−
1
)
2
n
−
1
×
(
p
i
−
1
)
p
i
n
i
−
1
\varphi(m)=(2-1)2^{n-1}\times(p_i-1)p_i^{n_i-1}
φ(m)=(2−1)2n−1×(pi−1)pini−1(因子减少
2
2
2,得证)
m
m
m为奇数:
m
=
p
i
n
i
m=p_i^{n_i}
m=pini(
p
i
p_i
pi全为奇数)
φ
(
m
)
=
(
p
i
−
1
)
p
i
n
i
−
1
\varphi(m)=(p_i-1)p_i^{n_i-1}
φ(m)=(pi−1)pini−1(p_i-1为偶数,转换为第一种情况,得证)
φ
(
m
)
\varphi(m)
φ(m)的复合函数预处理一下即可
(未完)
代码
#include<bits/stdc++.h>
#define ll long long
#define pii pair<ll,ll>
using namespace std;
const ll N=1e5+10;
ll n,m;
ll arr[N];
ll q;
map<ll,ll> phi;
inline ll getphi(ll x) {
if(phi[x])
return phi[x];
ll t=x;
ll ans=1;
for(ll i=2; i*i<=x; i++) {
if(x%i==0) {
ans*=i-1;
x/=i;
while(x%i==0) {
ans*=i;
x/=i;
}
}
}
if(x!=1)
ans*=x-1;
return phi[t]=ans;
}
inline ll exeuler(ll x,ll mod) {
if(x<mod)
return x;
return x%mod+mod;
}
inline ll pow(ll a,ll x,ll mod) {
ll ans=1;
while(x) {
if(x&1)
ans=exeuler(ans*a,mod);
a=exeuler(a*a,mod);
x>>=1;
}
return ans;
}
inline ll query(ll l,ll r,ll mod) {
if(l==r)
return exeuler(arr[l],mod);
if(mod==1)
return 1;
return pow(arr[l],query(l+1,r,getphi(mod)),mod);
}
void solve() {
scanf("%lld%lld",&n,&m);
for(ll i=1; i<=n; i++)
scanf("%lld",&arr[i]);
scanf("%lld",&q);
while(q--) {
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",query(l,r,m)%m);
}
}
int main() {
solve();
return 0;
}