zoukankan      html  css  js  c++  java
  • 2019ICPC南京网络赛B super_log——扩展欧拉定理

    题目

    设函数

    $$log_a*(x) = egin{cases}
    -1, & ext{ if } x < 1 \
    1+log_a*(log_ax) & ext{ if } x geq 1
    end{cases}$$

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

    分析

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

     由欧拉降幂公式

    $$a^b= egin{cases} a^{b \% varphi(p)} &  gcd(a,p)=1 \  a^b &  gcd(a,p) eq 1,b < varphi (p) \  a^{b\% varphi (p) + varphi (p)} & gcd(a,p) eq 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
    ", 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
    ", 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
    ", 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
    ", f(p, b));
        }
        return 0;
    }
    View Code

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

  • 相关阅读:
    Spring Session Logout
    VC6.0 error LNK2001: unresolved external symbol _main解决办法
    JDBC数据库编程基本流程
    JDBC连接SQL Server2008
    JDK的下载、安装及环境变量的配置
    奇数阶幻方口诀
    ping: sendto: Network is unreachable
    new/delete和malloc/free的区别
    MFC的消息管理
    VC++之自定义消息
  • 原文地址:https://www.cnblogs.com/lfri/p/11445393.html
Copyright © 2011-2022 走看看