洛谷P4139 上帝与集合的正确用法 题解

博客解析了洛谷P4139题目的解决方案,利用扩展欧拉定理和递归处理无穷数列2的幂次模p的计算。通过证明在n足够大时,模运算结果为常数,将问题转化为求解φ(p)。代码实现中使用龟速乘避免了long long溢出,并对比了筛法与非筛法在时间复杂度上的差异。
摘要由CSDN通过智能技术生成

洛谷P4139 上帝与集合的正确用法 题解

题目链接:P4139 上帝与集合的正确用法

题意

有无穷数列
a 0 = 1 , a n = 2 a n − 1 a_0=1,a_n=2^{a_{n-1}} a0=1,an=2an1
n → + ∞ n \to +\infty n+ 时,计算
a n   m o d   p a_n \bmod p anmodp

2 2 2 . . . 2   m o d   p {2}^{{2}^{{2}^{{.}^{{.}^{{.}^{2}}}}}} \bmod p 222...2modp
可以证明 a n   m o d   p a_n\bmod p anmodp n n n 足够大时为常数

多组数据 1 ≤ Q ≤ 1 0 3 1\le Q\le 10^3 1Q103 1 ≤ p ≤ 1 0 7 1 \le p\le 10^7 1p107

其实这个题很简单

根据扩展欧拉定理,有
a b ≡ { a b , b < φ ( m ) a b     m o d     φ ( m ) + φ ( m ) , b ≥ φ ( m ) ( m o d m ) \begin{aligned} a^b \equiv \begin{cases} a^b,&b< \varphi(m)\\\\ a^{b \ \bmod \ \varphi(m)+\varphi(m)},&b\ge \varphi(m) \end{cases} \pmod{m} \end{aligned} abab,ab mod φ(m)+φ(m),b<φ(m)bφ(m)(modm)
显然当 n n n 足够大时,有 a n − 1 > φ ( p ) a_{n-1} > \varphi(p) an1>φ(p)


a n   m o d   p = 2 a n − 1   m o d    φ ( p ) + φ ( p )   m o d   p a_{n}\bmod p = 2^{a_{n-1}\bmod\, \varphi(p)+\varphi(p)}\bmod p anmodp=2an1modφ(p)+φ(p)modp
可以发现原问题转化为了求解
a n − 1   m o d   φ ( p ) + φ ( p ) a_{n-1} \bmod \varphi(p) + \varphi(p) an1modφ(p)+φ(p)
递归处理即可

关于这个递归为什么是 O ( log ⁡ p ) O(\log p) O(logp)

显然每一次递归 p p p 都会变成 φ ( p ) \varphi(p) φ(p)

根据欧拉函数的公式

n = ∏ i = 1 s p i k i n=\prod_{i=1}^{s}p_i^{k_i} n=i=1spiki
φ ( n ) = n ∏ i = 1 s ( p i − 1 p i ) \varphi(n) = n \prod\limits_{i=1}^s\left(\dfrac{p_i-1}{p_i}\right) φ(n)=ni=1s(pipi1)
观察函数,可以发现

  • n n n 为偶数时,一定会把 2 2 2 提出来变成 1 1 1 ,也就是至少除以 2 2 2
  • n n n 为奇数时,一定会把一个素因子提出来变成一个偶数,也就是产生了 2 2 2 这个因子
  • 重复以上的过程直到 n = 1 n=1 n=1 结束

因此是 O ( log ⁡ p ) O(\log p) O(logp)

所以总的时间复杂度为 O ( Q p log ⁡ p ) O(Q\sqrt{p}\log p) O(Qp logp)

不用线性筛跑得反而快,因为 p p p 蛮大的,用了就变成 O ( p + Q log ⁡ p ) O(p+Q\log p) O(p+Qlogp)

数比较大,快速幂可能会爆了 long long \text{long long} long long ,所以要用龟速乘或者__int128

代码如下

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
int phi(int n)
{
    int ans=n;
    for(int i=2; i<=n/i; i++)
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0)n/=i;
        }
    if(n>1)ans=ans/n*(n-1);
    return ans;
}
int qpow(int a,int b,int p)
{
    int ans=1,base=a%p;
    while(b)
    {
        if(b&1)ans=(__int128)ans*base%p;
        base=(__int128)base*base%p;
        b>>=1;
    }
    return ans;
}
int solve(int p)
{
    if(p==1)return 0;
    return qpow(2,solve(phi(p))+phi(p),p);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q,p;
    cin >> Q;
    while(Q--)
    {
        cin >> p;
        cout << solve(p) << endl;
    }
    return 0;
}

用筛法求 φ ( p ) \varphi(p) φ(p) 跑了 1.52s,非筛法反倒就跑了114ms

转载请说明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值