题目

设函数

$$log_a*(x) = \begin{cases}

-1, & \text{ if } x < 1 \\

1+log_a*(log_ax) & \text{ if } x \geq 1

\end{cases}$$

求最小的正整数 $x$,使得 $log_a*(x) \geq b$ 

分析

通过将递归式展开,展开 $b$ 次等于1,所以 $x$ 为 $a^{a^{a^{...}}}$(共 $b$ 次)

 由欧拉降幂公式

$$a^b= \begin{cases} a^{b \% \varphi(p)} &  gcd(a,p)=1 \\  a^b &  gcd(a,p)\neq 1,b < \varphi (p) \\  a^{b\% \varphi (p) + \varphi (p)} & gcd(a,p)\neq 1,b \geq \varphi (p) \end{cases}$$

用这个公式,需要讨论 $b$ 与 $\varphi(p)$ 的大小关系,很麻烦。

看网上的博客,有一种精妙的方法,只需重写 Mod 函数,就能当作 $a$ 与 $p$ 互素处理。证明见 博客。

要点:

  • 快速幂和cal函数都要换成Mod;
  • 最终答案需要模p



#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll a, b, p;

ll Mod(ll x, ll mod)
{
return x < mod ? x : x % mod + mod;
}

ll euler_phi(ll n)
{
ll m = (ll)sqrt(n + 0.5);
ll ans = n;
for (ll i = 2; i <= m; i++)
{
if (n % i == 0)
{
ans = ans / i * (i - 1);
while (n % i == 0) n /= i; //除尽
}
}
if (n > 1) ans = ans / n * (n - 1); //剩下的不为1,也是素数
return ans;
}

ll qpow(ll a, ll b, ll p)
{
ll ret = 1;
while(b)
{
if(b&1) ret = Mod(ret * a, p);
a = Mod(a * a ,p);
b >>= 1;
}
return ret;
}

ll cal(ll a, ll b, ll p) //a^a^a..^a共b次
{
// printf("%lld %lld\n", t, p);
//if(t == 1) return Mod(a, p);
if(b == 0) return Mod(1, p);
if(p == 1) return Mod(a, p);
ll phip = euler_phi(p);
return qpow(a, cal(a, b-1, phip), p); //第一类和第三类
}

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%lld%lld%lld", &a, &b, &p);
printf("%lld\n", cal(a, b, p) % p); //这个取模不能少
}
return 0;
}


 

之前写了一种需要讨论 $b$  与 $\varphi(p)$ 大小的,

因为模数 $p \leq 1e6$,可以找找 $b$ 小于 $\varphi(p)$ 的情况

打表发现,



1 2 4 16 65536
1 3 27 97484987 739387
1 4 256 6084096 61392896
1 5 3125 8203125 8203125
1 6 46656 63878656 38438656
1 7 823543 70132343 33172343
1 8 16777216 21126656 19449856
1 9 87420489 27177289 45865289


当次数大于3时,只有 $a=2$ 可能小于 $\varphi(p)$,特判一下就好了。


2019ICPC南京网络赛B super_log——扩展欧拉定理_#include2019ICPC南京网络赛B super_log——扩展欧拉定理_c++_02


#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll a, b, p;
int table[10] = {1, 2, 4, 16,65536};

ll qpow(ll a, ll b, ll p)
{
a = a%p;
ll ret = 1%p;
while(b)
{
if(b&1) ret = ret*a%p;
a = a*a%p;
b >>= 1;
}
return ret%p;
}

ll euler_phi(ll n)
{
ll m = (ll)sqrt(n + 0.5);
ll ans = n;
for (ll i = 2; i <= m; i++)
{
if (n % i == 0)
{
ans = ans / i * (i - 1);
while (n % i == 0) n /= i; //除尽
}
}
if (n > 1) ans = ans / n * (n - 1); //剩下的不为1,也是素数
return ans;
}

ll f(ll p, ll t)
{
//printf("%lld %lld\n", p, t);
if(t == 1) return a%p;
if(t == 2) return qpow(a, a, p);
if(t == 0) return 1%p;
if(p == 1) return 0;
ll phip = euler_phi(p);
if(p % a == 0) //t >= 3,若出现第二种情况,a只能为2
{
if(a == 2 && t <= 4 && table[t-1] < phip)
//return qpow(a, f(p, t-1), p);
return table[t]%p;
}
return qpow(a, f(phip, t-1)+phip, p); //第一类和第三类
}

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%lld%lld%lld", &a, &b, &p);
printf("%lld\n", f(p, b));
}
return 0;
}

View Code

 

 


个性签名:时间会解决一切