CF906D Power Tower
知识点:拓展欧拉定理、记忆化、欧拉函数、快速幂
题意
给定序列 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;
}