2019ICPC南京网络赛B super_log——扩展欧拉定理

Posted lfri

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019ICPC南京网络赛B super_log——扩展欧拉定理相关的知识,希望对你有一定的参考价值。

题目

设函数

$$log_a*(x) = \\begincases
-1, & \\text if x < 1 \\\\
1+log_a*(log_ax) & \\text if x \\geq 1
\\endcases$$

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

分析

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

 由欧拉降幂公式

$$a^b= \\begincases 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) \\endcases$$

用这个公式,需要讨论 $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)$,特判一下就好了。

技术图片
#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

 

 

参考链接:https://blog.csdn.net/qq_35914587/article/details/79883547

以上是关于2019ICPC南京网络赛B super_log——扩展欧拉定理的主要内容,如果未能解决你的问题,请参考以下文章

2019ICPC网赛南京站B题 super_log(欧拉降幂

super_log (广义欧拉降幂)(2019南京网络赛)

2019ICPC南京网络赛A题 The beautiful values of the palace(三维偏序)

2019icpc南京网络赛 A 主席树

2019ACM-ICPC南京网络赛Holy Grail (SPFA模板题)

2019-ACM-ICPC-南京区网络赛-D. Robots-DAG图上概率动态规划