Linux下安裝中文字型
阿新 • • 發佈:2021-12-10
題意:\(T\)組資料,對於每個模數\(p\),求\(2^{2^{2^{...}}} mod\) \(p\),\(T\le 10^3\),\(p\le 10^7\)
思路:擴充套件尤拉定理
顯然\({2^{2^{...}}}\)這個無限數,是大於\(\varphi(p)\)的,那麼由擴充套件尤拉定理可得:
對於\(b\ge \varphi(p)\),
有\(a^b\equiv a^{b\ mod\ \varphi(p)+\varphi(p)}\ mod\ p\)
很顯然這個是遞迴式子,模數\(\varphi(p)\)很快會降為\(1\),此時式子為\(0\)
對於\(\varphi(p)\)
時間複雜度:\(O(p+Tlog\ p)\)
接下來我們談一下,如何用線性篩預處理尤拉函式\(\varphi(x)\)
對於\(\varphi(x)\)我們利用如下性質:
- \(\varphi(x)=x-1\),\(x\in prime\)
- \(\varphi(x^k)=x^k-x^{k-1}\),\(x\in prime\)
- \(gcd(m,n)=1\),\(\varphi(mn)=\varphi(m) \varphi(n)\)
由此,我們得到尤拉函式是個積性函式,而線性篩可以預處理積性函式
Code:
bool vis[N]; int cnt,prime[N/10],phi[N],p,t; void get_phi(int n){ phi[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]){ prime[++cnt]=i; phi[i]=i-1; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } }
套用這個模板,本題就很容易了
Code:
#include <bits/stdc++.h> using namespace std; const int N=1e7+10; typedef long long ll; bool vis[N]; int cnt,prime[N/10],phi[N],p,t; void get_phi(int n){ phi[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]){ prime[++cnt]=i; phi[i]=i-1; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } int power(int a,int b,int p){ int res=1; for(;b;b>>=1){ if(b&1) res=1LL*res*a%p; a=1LL*a*a%p; } return res; } int solve(int x){ if(x==1) return 0; return power(2,solve(phi[x])+phi[x],x); } int main(){ get_phi(N); cin>>t; while(t--){ cin>>p; cout<<solve(p)<<endl; } return 0; }