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(...ar1ar)))

思路

拓展欧拉定理:
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) acac%φ(m)+φ(m)if cφ(m)
a c ≡ a c i f   c < φ ( m ) a^c\equiv a^c \quad if \ c< \varphi(m) acacif 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)=(21)2n1×(pi1)pini1(因子减少 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)=(pi1)pini1(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;
}
全部评论

相关推荐

11-15 18:39
已编辑
西安交通大学 Java
全村最靓的仔仔:卧槽,佬啥bg呢,本也是西交么
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务