【BZOJ3884】上帝与集合的正确用法(欧拉定理,数论)

【BZOJ3884】上帝与集合的正确用法(欧拉定理,数论)

题面

BZOJ

题解

我们有欧拉定理:
\(b \perp p\)

\[a^b≡a^{b\%\varphi(p)}\pmod p \]

否则
\(b≥\varphi(p)\)

\[a^b≡a^{b\%\varphi(p)+\varphi(p)}\pmod p \]

这道题里面\(2\)的无穷次方显然会比\(\varphi(p)\)
所以,递归调用这个公式
因此每次\(p\)都会变成\(\varphi(p)\)
所以,\(\varphi(p)\)必定会不断缩小
当其变成\(1\)的是否就不用再算下去了
直接返回\(0\)就好

回朔的时候快速幂算一下就可以啦

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
ll phi(ll x)
{
	ll ret=x;
	for(int i=2;i*i<=x;++i)
		if(x%i==0)
		{
			ret=ret/i*(i-1);
			while(x%i==0)x/=i;
		}
	if(x>1)ret=ret/x*(x-1);
	return ret;
}
ll fpow(ll a,ll b,ll p)
{
	ll s=1;
	while(b){if(b&1)s=1ll*s*a%p;a=1ll*a*a%p;b>>=1;}
	return s;
}
ll Query(int P)
{
	if(P==1)return 0;
	ll x=phi(P);
	return fpow(2,Query(x)+x,P);
}
int main()
{
	int T=read();
	while(T--)
		printf("%lld\n",Query(read()));
	return 0;	
}

posted @ 2018-01-19 19:53  小蒟蒻yyb  阅读(375)  评论(0编辑  收藏  举报