(一) 几个基本定义
/*虽然我们不需要知道怎么证明欧拉函数,但是它是个啥还是要知道的*/
1) 欧拉函数:
定义:对于一个正整数n,小于n且和n互质的正整数的个数,记做φ(n),φ(1)被定义为1
性质:显然,对于质数p,q,满足φ(n) =(p-1)(q-1)=pq+1-pq/p-pq/q
性质:显然,对于质数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;
}
}