洛谷P4139 上帝与集合的正确用法 & CF906D Power Tower

P4139 上帝与集合的正确用法

考虑扩展欧拉定理:

(a^bequiv egin{cases}a^{bmod varphi(p)+varphi(p)}& (bge varphi(p))\ a^b & (b<varphi(p))end{cases}pmod p)

对于本题,(2^{2^{2^{cdots}}}) 的指数 (b=2^{2^{cdots}}) ,显然足够大

(2^{2^{2^{cdots}}}equiv 2^{2^{2^{cdots}}mod varphi(p)+varphi(p)}pmod p)

指数上的 (2^{2^{cdots}}mod varphi(p)) 也同理,可以一直递归算下去

因为 (varphi(p)<p) ,所以最终模数一定会降至 (1) ,此时即可停止递归

事实上,考虑小于 (p) 的任意数 (i) ,有 (gcd(i,p)=gcd(p-i,p))
所以 (i)(p-i) 要么同时与 (p) 互质,要么同时与 (p) 不互质
易证对任意 (p>2)(varphi(p)) 必为偶数

(varphi(p)) 含有因子 (2) ,因此 (varphi(varphi(p))ledfrac12varphi(p))
所以 (varphi(p)) 是指数级递减的,递归层数为 (O(log p)) 级别

所以直接这样写就可以了
时间复杂度为 (O(p+Tlog^2p)) (线性筛预处理 (varphi) )或 (O(Tsqrt plog p+Tlog^2p)) (暴力算 (varphi)
第一种显然稳过 第二种其实完全跑不满 也可以轻松AC

#include<stdio.h>
int T,cnt,t,p,s,i,a[50];
int phi(int x) {
	for (s=x,i=2; i*i<=x; ++i)
		if (x%i==0) {
			s=s/i*(i-1);
			while (x%i==0) x/=i;
		}
	return x>1&&(s=s/x*(x-1)),s;
}
int power(int x,int y,int p) {
	for (s=1; y; y>>=1)
		(y&1)&&(s=1ll*s*x%p),x=1ll*x*x%p;
	return s+p;
}

int main() {
	for (scanf("%d",&T); T; --T) {
		scanf("%d",&p),cnt=0,t=1;
		if (p==1) { puts("0"); continue; } 
		while (p>1) a[++cnt]=p,p=phi(p);
		for (i=cnt; i; --i) t=power(2,t,a[i]);
		printf("%d
",t%a[1]);
	}
	return 0;
}

CF906D Power Tower

看起来像是用某种很牛b的数据结构维护(?)
但再想想就发现这题也是用个扩欧就行了
这次的幂运算是有限次的 其实比无限的麻烦一点 要加点细节
时间复杂度为 (O(n+sqrt plog p+qlog^2p))

#include<stdio.h>
typedef long long ll;
int n,m,q,l,r,cnt,s,i,p[40],a[100010];
inline int mod(ll x,int p) { return (x<p?x:x%p+p); }
inline int power(int x,int y,int p) {
	for (s=1; y; y>>=1)
		(y&1)&&(s=mod(1ll*s*x,p)),x=mod(1ll*x*x,p);
	return s;
}
int phi(int x) {
	for (s=x,i=2; i*i<=x; ++i) if (x%i==0) {
		s=s/i*(i-1);
		while (x%i==0) x/=i;
	}
	return x>1&&(s=s/x*(x-1)),s;
}

int f(int i,int r,int x) {
	if (x>cnt) return 1;
	if (i==r) return mod(a[i],p[x]);
	return power(a[i],f(i+1,r,x+1),p[x]);
}
int main() {
	scanf("%d%d",&n,&m),p[1]=1;
	while (m>1) p[++cnt]=m,m=phi(m);
	for (i=1; i<=n; ++i) scanf("%d",a+i);
	for (scanf("%d",&q); q; --q)
		scanf("%d%d",&l,&r),
		printf("%d
",f(l,r,1)%p[1]);
	return 0;
}
原文地址:https://www.cnblogs.com/REKonib/p/15054474.html