首页 > 其他分享 >上帝与集合的正确用法——欧拉定理

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

时间:2022-11-30 22:58:48浏览次数:34  
标签:上帝 phi int 定理 元素 varphi 用法 欧拉

上帝与集合的正确用法

题目描述

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

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

第二天,上帝创造了一个新的元素,称作 \(\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)\)为定值

标签:上帝,phi,int,定理,元素,varphi,用法,欧拉
From: https://www.cnblogs.com/oierpyt/p/16940061.html

相关文章

  • Linux中&&和&,|和||用法及区别详解!
    在使用Linux命令时,我们往往可以一行执行多条命令,或者有条件的执行下一条命令,对于刚接触Linux命令时,特殊符号绝对是最困扰的事情之,本篇文章将为大家详细介绍下&&和&,|和||的......
  • Python 中 -m 的典型用法、原理解析与发展演变
    在命令行中使用Python时,它可以接收大约20个选项(option),语法格式如下:python[-bBdEhiIOqsSuvVWx?][-ccommand|-mmodule-name|script|-][args]本文想要聊聊比较......
  • Solidity 函数及修改器(modifier)的用法
    //SPDX-License-Identifier:MITpragmasolidity^0.8.13;contractFunction{//多返回值函数functionreturnMany()publicpurereturns......
  • Solidity中view和pure的用法
    getter类型的函数可以被view或者pure修饰。view修饰的函数不能改变状态变量。pure则既不能改变状态变量,也不取读取状态变量。//SPDX-License-Identifier:MITpragma......
  • 主定理学习笔记
    分析复杂度时可能有用。(主定理狗都不学)若有递归式\(T(n)=aT(\dfrac{n}{b})+f(n)\)则分以下三种情况:\(f(n)=O(n^{\log_ba-\epsilon}),\epsilon>0\),此时\(T(n)=\The......
  • stream用法记录
    转自:https://blog.csdn.net/sc179/article/details/126283897JavaStream类常见用法目录1基本过滤:返回学生列表中90分以上的2基本转换:根据学生列表返回名称......
  • using关键字在C#中的用法
    using关键字有两个主要用途: (一).作为指令,用于为命名空间创建别名或导入其他命名空间中定义的类型。 (二).作为语句,用于定义一个范围,在此范围的末尾将释放对象。(一).......
  • C#--泛型委托Action<T>、Func<T>、Predicate<T>的解析和用法
    C#中的委托(Delegate)类似于C或C++中函数的指针。委托是保存对某个方法引用的一种引用类型变量。若要引用的方法,具有两个参数没有返回值,使用Action<T1, T2>委托,则不需要......
  • var_dump()的用法
    var_dump()voidvar_dump(mixedexpression[,mixedexpression[,...]])var_dump()方法是判断一个变量的类型与长度,并输出变量的数值,如果变量有值输的是变量的值......
  • Gson基本用法
    Gson解析json数据数组Gsongson=newGson();List<Person>people=gson.fromJson(jsonData,newTypeToken<List<Person>>(){}.getType());解析json数据Gsongson=new......