上帝与集合的正确用法——欧拉定理

上帝与集合的正确用法

题目描述

根据一些书上的记载,上帝的一次失败的创世经历是这样的:

第一天,上帝创造了一个世界的基本元素,称做元。

第二天,上帝创造了一个新的元素,称作 \(\alpha\)\(\alpha\) 被定义为元构成的集合。容易发现,一共有两种不同的 \(\alpha\)

第三天,上帝又创造了一个新的元素,称作 \(\beta\)\(\beta\) 被定义为 \(\alpha\) 构成的集合。容易发现,一共有四种不同的 \(\beta\)

第四天,上帝创造了新的元素 \(\gamma\)\(\gamma\) 被定义为 \(\beta\) 的集合。显然,一共会有 \(16\) 种不同的 \(\gamma\)

如果按照这样下去,上帝创造的第四种元素将会有 \(65536\) 种,第五种元素将会有 \(2^{65536}\)种。这将会是一个天文数字。

然而,上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来,因此,日复一日,年复一年,他重复地创造着新的元素……

然而不久,当上帝创造出最后一种元素 \(\theta\) 时,他发现这世界的元素实在是太多了,以致于世界的容量不足,无法承受。因此在这一天,上帝毁灭了世界。

至今,上帝仍记得那次失败的创世经历,现在他想问问你,他最后一次创造的元素 \(\theta\) 一共有多少种?

上帝觉得这个数字可能过于巨大而无法表示出来,因此你只需要回答这个数对p取模后的值即可。

你可以认为上帝从 \(\alpha\)\(\theta\) 一共创造了 \(10^9\) 次元素,或 \(10^{18}\) 次,或者干脆 \(\infty\) 次。

一句话题意:

定义 \(a_0=1,a_n=2^{a_{n-1}}\),可以证明 \(a_n\bmod p\)\(n\) 足够大时为常数,求这个常数。

输入格式

第一行一个整数 \(T\),表示数据个数。

接下来 \(T\) 行,每行一个正整数 \(p\),代表你需要取模的值。

输出格式

\(T\) 行,每行一个正整数,为答案对 \(p\) 取模后的值。

样例 #1

样例输入 #1

3
2
3
6

样例输出 #1

0
1
4

提示

对于 \(100\%\) 的数据,\(T\le 10^3\)\(p\le10^7\)

题解

关于非质数的余数,考虑使用欧拉定理求解

原式=\(2^{2^{2^{2^{2...}}}} \equiv 2^{2^{2^{2...}}\bmod \varphi(p)+\varphi(p)} \equiv 2^{2^{2^{2...}\bmod \varphi(\varphi(p))+\varphi(\varphi(p))}\bmod p+\varphi(p)}\)

显然这是一个递归式,考虑题设条件,何时为一个定值.

因为\(\forall i\ge 2,\varphi(i)\le i\),所以即使不断嵌套下去,最后的递归的模数会变成1,这样的话即使继续递归,模1也永远是0,再无意义,我们再回带就可以得到题目所说的定值

写出代码就是:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
#define N 10000050
int phi[N], prime[1000050], tot, cnt, p, n, ans;
void init() {
	phi[1] = 1;
	for (int i = 2; i <= N; i++) {
		if (!phi[i]) {
			prime[++cnt] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= cnt; j++) {
			if (prime[j] * i > N)break;
			int x = prime[j] * i;
			phi[x] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
		}
	}
}
int power(int a, int b, int p) {
	int ans = 1;
	while (b) {
		if (b & 1)ans = ans * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return ans;
}
int dfs(int p) {
	//	printf("%lld\n",p);
	if (p == 1)return 0;
	return power(2, dfs(phi[p]) + phi[p], p);
}
signed main() {
	init();
	scanf("%lld", &p);
	while (p--) {
		scanf("%lld", &n);
		printf("%lld\n", dfs(n) % n);
	}
}

这题因为卡空间只能写埃氏筛法

再来,那么函数

int dfs(int p) {
	//	printf("%lld\n",p);
	if (p == 1)return 0;
	return power(2, dfs(phi[p]) + phi[p], p);
}

复杂度如何保证?
引理:足够大的数的欧拉函数至多是本身的一半(向上取整)

证明:

偶数的欧拉函数是本身一半,因为所有奇数都与其互质,而奇数的欧拉函数也至多是半身一本,因为所有偶数都与其互质

故函数最多递归\(\log p\)层,再套上快速幂,复杂度为\(O(T\log^2 P)\),复杂度正确

关于本题:

欧拉定理的推论:

设数列\(a_0=1,a_n=x^{a_{n-1}}\),\(x\)是正整数

求证: 当\(n\)足够大时,一定有\(a_m\bmod p(m\ge n)\)为定值

posted @ 2022-11-30 22:44  spdarkle  阅读(127)  评论(0编辑  收藏  举报