星星之火

[BZOJ3884] 上帝与集合的正确用法 (欧拉函数)

题目链接:  https://www.lydsy.com/JudgeOnline/problem.php?id=3884

题目大意:

给出 M, 求 $2^{2^{2^{2^{...}}}}$ % M 的值. p ≤ 1e9

题解:

我们设 M = $2^k$*p , p是奇数

$2^{2^{2^{2^{...}}}}$ % M =  $2^k$ * ($2^{2^{2^{2^{...}}}-k}$ % p)

因为p是奇数,所以p与2互质,我们可以用欧拉定理

原式化为

可以递归地做下去

但模数变成1的时候直接返回0就好了

参考某大佬博客的时间复杂度:

AC代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;

int T;
inline int read()
{
    char ch=getchar();
    int s=0,f=1;
    while (!(ch>='0'&&ch<='9')) {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
int qpow(ll a,int b,int m)
{
    ll res=1;
    for (;b;b>>=1,a=a*a%m) if (b&1) res=res*a%m;
    return res%m;
}
int phi(int x)
{
    int res=x;
    for (int i=2;i*i<=x;i++)
    {
        if (x%i) continue;
        res/=i;res*=i-1;
        while (x%i==0) x/=i;
    }
    if (x>1) res/=x,res*=x-1;
    return res;
}
int solve(int p)
{
    if (p==1) return 0;
    int k=0;
    while (~p&1) p>>=1,k++;
    int phi_p=phi(p);
    int re=solve(phi_p);
    re=(re+phi_p-k%phi_p)%phi_p;
    re=qpow(2,re,p);
    return re<<k;
}
int main()
{
    T=read();
    while (T--)
    {
        int p=read();
        printf("%d\n",solve(p));
    }    
    return 0;
}

 

posted @ 2018-08-25 16:51  星星之火OIer  阅读(213)  评论(0编辑  收藏  举报