(一) 几个基本定义
/*虽然我们不需要知道怎么证明欧拉函数,但是它是个啥还是要知道的*/
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; } }