B. super_log(2019ICPC区域网络赛南京站)

题目链接:https://nanti.jisuanke.com/t/41299

题目大意

已知函数 l o g a log_a^* 形式如下:
l o g a ( x ) = { 1 , if x<1 1 + l o g a ( l o g a x ) , if x 1 log_a^*(x)= \begin{cases} -1 & \text{, if x<1} \\ 1+log_a^*(log_ax) & \text{, if x} \geq1 \end{cases}
现在给出 a , b , m a,b,m ,要找到最小的正整数 x x ,使得 l o g a ( x ) b log_a^*(x) \geq b 。由于 x x 可能很大,所以需要取模 m m

题目分析

多造几组 a , b a,b 去算 x x ,可以发现这个问题就是求:
a a a . . . b  times m o d m \underbrace{a^{a^{a^{...}}}}_{b \text{ times}} mod \, m

因为暴力求这个数的过程量会非常大,所以需要对过程量取模。但是过程量是指数,我们不能直接对其取模,这里就需要用上欧拉降幂。
a b { a b % φ ( p ) ( m o d p ) gcd(a, p)=1 a b ( m o d p ) b < φ ( p ) a b % φ ( p ) + φ ( p ) ( m o d p ) b φ ( p ) a^b \equiv \begin{cases} a^{b\% \varphi(p)} \, (mod \, p) & \text{, \,gcd(a, p)=1} \\ a^b \quad (mod \, p) & \text{, \, b <} \varphi(p) \\ a^{b\% \varphi(p) + \varphi(p)} \, (mod \, p) & \text{, \, b} \geq \varphi(p) \\ \end{cases}
知道了这些就里答案很接近了,我们可以每次都把问题递归分解为求利用欧拉降幂解指数部分的值,回归时再计算层指数运算的结果。

要注意:除了分解了 b b 次可以返回之外,欧拉函数迭代到1也可以提前返回,可以减少大量不必要的运算。

黑历史记录:

  • 没有想到模数的欧拉函数迭代到1可以提前返回的情况,因为任何正整数取模1都等于0,所以没必要再继续运算。
  • 没有考虑到欧拉函数迭代到1是返回值为0时的处理1。

代码如下

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int T, a, b ,m;
int phi[maxn];
ll prime[maxn];
bool vis[maxn];
//快速幂
ll quick_pow(ll x, ll n, ll Mod) {
    ll res = 1;
    while (n) {
        if (n & 1) res = (res * x) % Mod;
        x = (x * x) % Mod;
        n >>= 1;
    }
    return res;
}
//线性筛筛求欧拉函数
void getphi(int n) {
    int i, j, tot = 0;
    phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            prime[++tot] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= tot && i * prime[j] <= n; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            } else {
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    }
}

int dfs(int a, int b, int m) {
	//欧拉函数迭代到1
    if (m == 1) return 0;
    //已经迭代到最后一次了
    if (b == 0) return 1;
    int x = dfs(a, b - 1, phi[m]);
    //x为0是欧拉函数迭代到1返回的
    if (x < phi[m] && x) return quick_pow(a, x, m);
    else return quick_pow(a, x + phi[m], m);
}

int main()
{
    getphi(maxn-10);
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d %d", &a, &b, &m);
        printf("%d\n", dfs(a, b, m));
    }
    return 0;
}

参考链接

  1. https://www.cnblogs.com/ACMLCZH/p/8117161.html?tdsourcetag=s_pctim_aiomsg
发布了59 篇原创文章 · 获赞 103 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42292229/article/details/101346418