欧拉函数及其应用

(一) 几个基本定义
/*虽然我们不需要知道怎么证明欧拉函数,但是它是个啥还是要知道的*/
 1) 欧拉函数:
     定义:对于一个正整数n,小于n且和n互质的正整数的个数,记做φ(n),φ(1)被定义为1
     性质:显然,对于质数p,q,满足φ(n) =(p-1)(q-1)=pq+1-pq/p-pq/q
 下面是求欧拉函数的方法:
ll euler(ll n){
	int cnt=n,nownum=n;
	for(ll i = 2 ; i*i <= nownum ; i ++)
		if(nownum % i == 0){
			cnt -= cnt/i;      //标记1
			while(nownum % i == 0)
				nownum /= i;
		}
	if(nownum > 1)
		cnt -= cnt/nownum;
	return cnt; 
}
在标记1的地方其实是涉及到了一个数学的知识,虽然具体的我也没有弄得很明白(毕竟会用为准嘛),但大致就是,如果一个数n有一个因子3和一个因子5,把1到n中间所有是3的倍数的数划掉以后,在剩下的(n-n/3)个数中,5的倍数的数出现的次数就是(n-n/3)/5。比如:n=20,去掉5的倍数的数,还剩1,2,3,4,6,7,8,9,11,12,13,14,16,17,18,19,其中2的倍数的数还有8个,而(20-20/5)/2=8个,所以标记1这样写是没有问题的,具体的证明嘛。。。。。我就不会了
 2) 欧拉定理:
     定义:a^(φ(n)+1) mod n = a , a和n为互质的正整数
     /*上面讲的其实没有什么用的,一般解题时完成降幂任务的东西就是下面这个式子了*/
     推广:a^b ≡ a^(b%φ(n)+φ(n)) mod n ,当b<=φ(m)时直接用快速幂即可
      所以,由这个式子我们发现,当b非常大的时候,可以把它降成b%φ(n)+φ(n),从而达成了降幂的效果。
(二)例题1: 点击打开链接
  一句话题意就是:求f(n) = 2^f(n-1) mod p,n默认为10^9,f(1) = 1,p由数据输入给出
AC代码:
#include<iostream>
using namespace std;
typedef long long ll;

ll euler(ll n){
	ll cnt = n, nownum = n;
	for(ll i = 2; i * i <= nownum; i++){
		if(nownum % i == 0){
			cnt -= (cnt / i);
			while(nownum % i == 0)
				nownum /= i;	
		}
	}
	if(nownum > 1)
		cnt -= (cnt/nownum);
//	cout << "euler:" << cnt << endl;
	return cnt;
} 
ll fast_mod(ll x, ll y, ll p){ // x^y % p
	ll ans = 1, tag = x; 
	while(y > 0){
		if(y & 1)
			ans = (ans * tag) % p;
		tag = (tag * tag) % p;
		y >>= 1;
	}
//	cout << "fast_mod:" << ans << endl; 
	return ans;
}
ll func(ll n, ll p){  //f(n-1) % &p + &p
//	printf("func(%lld)\n",&n);
	if(p == 1)
		return 0;
	if(n == 1)
		return 1;
	if(n == 2)
		return 2 % p;
	if(n == 3)
		return 4 % p;
	if(n == 4)
		return 16 % p;
	else{
		ll e = euler(p);
		ll a = func(n-1, e) + e;
		ll fn = fast_mod(2, a, p);	
		return fn;
	}
		
		
}
int main(){
//	cout << euler(1) << endl;
//	cout << euler(2) << endl;
//	cout << euler(3) << endl;
//	cout << fast_mod(2,3,1000) << endl;
//	cout << fast_mod(3,2,3) << endl;
//	cout << fast_mod(3,2,1000) << endl;

	int T, p;
	cin >> T;
	while(T--){
		cin >> p;
		cout << func(1000000000, p) << endl;
	}
	return 0;
} 
f(n) = 2^f(n-1) mod p;
即f(n) = 2^(f(n-1) mod φ(p) + φ(p)) mod p;
所以依靠递归函数实现,本来以为递归的终点是n==1时,后来调试的时候发现,其实递归终止一般是靠p==1的时候,因为φ(φ(φ(...φ(p))))这样降的时候肯定要比n每次减1降得快的。。。。而我原本加上这句的目的是为了防止题目输入的时候给出p=1,这样就不用算了,任何数模1都是0嘛,结果反而因为这个对了,所以一定不要忘记讨论p的情况。
(二)例题2:csu2021 链接没了,可以搜到的,其实与上面的题目是基本一样的,不过这里是f(n)=n^f(n-1) mod p
AC代码:
ll func(ll n,ll m){
	if(m == 1)
		return 0;
	if(n == 1)
		return 1;
	else if(n == 2)
		return 2%m;
	else if(n == 3)
		return 9%m;
	else if(n == 4)
		return fast_mod(4,9,m);
	else{
		ll e=euler(m);
		ll z=func(n-1,e);
		ll ans=fast_mod(n,e+z,m);
		return ans;
	}	
		
}



猜你喜欢

转载自blog.csdn.net/qq_37064135/article/details/80056514