Wraith_Fiee的博客

P4139 上帝与集合的正确用法

2021-11-18 · 4 min read
扩展欧拉定理 线性筛

原题传送门

题意:TT组数据,对于每个模数pp,求222...mod2^{2^{2^{...}}} mod ppT103T\le 10^3p107p\le 10^7

思路:扩展欧拉定理
显然22...{2^{2^{...}}}这个无限数,是大于φ(p)\varphi(p)的,那么由扩展欧拉定理可得:
对于bφ(p)b\ge \varphi(p)
abab mod φ(p)+φ(p) mod pa^b\equiv a^{b\ mod\ \varphi(p)+\varphi(p)}\ mod\ p
很显然这个是递归式子,模数φ(p)\varphi(p)很快会降为11,此时式子为00
对于φ(p)\varphi(p),我们可以用线性筛预处理得到
时间复杂度:O(p+Tlog p)O(p+Tlog\ p)

接下来我们谈一下,如何用线性筛预处理欧拉函数φ(x)\varphi(x)
对于φ(x)\varphi(x)我们利用如下性质:

  • φ(x)=x1\varphi(x)=x-1xprimex\in prime
  • φ(xk)=xkxk1\varphi(x^k)=x^k-x^{k-1}xprimex\in prime
  • gcd(m,n)=1gcd(m,n)=1,φ(mn)=φ(m)φ(n)\varphi(mn)=\varphi(m) \varphi(n)

由此,我们得到欧拉函数是个积性函数,而线性筛可以预处理积性函数
Code

bool vis[N];
int cnt,prime[N/10],phi[N],p,t;
void get_phi(int n){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&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);
		}
	}
}

套用这个模板,本题就很容易了
Code

#include <bits/stdc++.h>
using namespace std;
const int N=1e7+10;
typedef long long ll;
bool vis[N];
int cnt,prime[N/10],phi[N],p,t;
void get_phi(int n){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&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 power(int a,int b,int p){
	int res=1;
	for(;b;b>>=1){
		if(b&1) res=1LL*res*a%p;
		a=1LL*a*a%p;
	}
	return res;
}
int solve(int x){
	if(x==1) return 0;
	return power(2,solve(phi[x])+phi[x],x);
}
int main(){
	get_phi(N);
	cin>>t;
	while(t--){
		cin>>p;
		cout<<solve(p)<<endl;
	}
	return 0;
}
在吹不出褶皱的日子里发光
Powered by Gridea