1. 程式人生 > >擴充套件尤拉定理--luoguP4139 上帝與集合的正確用法

擴充套件尤拉定理--luoguP4139 上帝與集合的正確用法

傳送門

擴充套件尤拉定理

據說可以用來解決迴圈節問題

迴圈又分純迴圈和混迴圈

純迴圈:

如ax%b 它的迴圈節就是b/gcd(a,b),那麼x在[0,b)之內就有gcd(a,b)個取值

(a,b互質就是純迴圈,不互質就是混迴圈)

混迴圈:

迴圈節前面的一段尾巴來自於共有的約數p,是log級別的

迴圈節長度是phi(b)的約數

這道題就是一個擴充套件尤拉定理的應用

當a,b互質的時候它是一個純迴圈,就可以直接把指數不斷%phi(p)

當a,b不互質的時候,要把指數%phi(p)再加上phi(p)(當指數大於phi(p)時)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 1000001
#define LL long long
using namespace std;
int t,p,cnt;
LL pri[700000],phi[maxn];
bool vis[maxn];

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

inline void get_phi(){
	vis[1]=1; phi[1]=1;
	for(int i=2;i<maxn;i++){
		if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt && i*pri[j]<maxn;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0){
				phi[i*pri[j]]=phi[i]*pri[j];
				break;
			}
			phi[i*pri[j]]=phi[i]*(pri[j]-1);
		}
	}
}

inline LL qpow(LL x,int k,int mod){
	LL ret=1;
	while(k){
		if(k&1) (ret*=x)%=mod;
		(x*=x)%=mod; k>>=1;
	} return ret;
}

inline LL solve(int p){
	if(p==1) return 0;
	return qpow(2,solve(phi[p])+phi[p],p);
}

int main(){
	t=rd();
	get_phi(); cout<<cnt<<endl;
	while(t--){
		p=rd();
		printf("%lld\n",solve(p));
	}
	return 0;
}