原題CodeForces 906D Power Tower 有限冪塔函數模板(此題參考)
BZOJ 3884 無限次模板
一.題意及分析
題意:
求log*a(x)>=b,最小x
分析:
可以看出是單調遞增,顯然取等號,x最小
觀察可知,x>=1,不斷遞歸下去,左邊每次遞歸累加1,右邊log*a(F(x))中F(x)不斷取log,最終x=a時,F(x)=0,此時log*a=-1,加上左邊的1,正好抵消,所以共遞歸了b次(不包含最後一次),最後左邊累加的結果剛好就是b
因此實際求一個冪塔函數:
x = a^a^a^.........^a^a(一共b個a的高階冪)%m;
於是用歐拉降冪:(分析見上面,有限個冪塔函數模板題鏈接)
但注意特判a,b,mod=0 or 1
二.代碼
#include<bits/stdc++.h>
#define Mod(a,b) a<b?a:a%b+b //重定義取模,按照歐拉定理的條件
#define LL long long
#define N 100010
using namespace std;
LL n,q,mod,a;
map<LL,LL> mp;
LL qpow(LL x,LL n,LL mod)
{
LL res=1;
while(n)
{
if (n&1) res=Mod(res*x,mod),n--;
x=Mod(x*x,mod); n>>=1;
}
return res;
}
LL phi(LL k)
{
LL i,s=k,x=k;
if (mp.count(k)) return mp[x]; //記憶化存儲
for(i = 2;i * i <= k; i++)
{
if(k % i == 0) s = s / i * (i - 1);
while(k % i == 0) k /= i;
}
if(k > 1) s = s / k * (k - 1);
mp[x]=s; return s;
}
LL solve(LL l,LL r,LL mod)
{
if (l==r||mod==1) return Mod(a,mod); //如果到右端點或者φ值等於1,那麼直接返回當前數字
return qpow(a,solve(l+1,r,phi(mod)),mod); //否則指數爲[l+1,r]區間的結果
}
int main()
{
//scanf("%lld%lld",&n,&mod);
// for(int i=1;i<=n;i++)
//scanf("%lld",&a[i]);
scanf("%lld",&q);
while(q--)
{
LL L,R;
scanf("%lld%lld%lld",&a,&R,&mod);
if(mod == 1)//兩句特判必不可少,不然WA
printf("0\n");
else if(R== 0 || a == 1)
printf("1\n");
else
printf("%lld\n",solve(1,R,mod)%mod);
//對mod取模,因爲qpow內部是用Mod(a,b)取模
}
return 0;
}