[扩展欧拉定理例题]降幂大法
降幂大法1
题面:
给出a,b,p,计算a^b %p 的结果,0< a <= 10^9,0< b <= 10^10000,0< p <= 10^9。
思路:
10的10000次方,这题不简单。那么经过欧拉定理的学习之后,有如下结论:,其中a,n互质,但是很显然,他不能用来解决这道题。那么扩展欧拉定理应运而生了。
ac≡acmodφ(m)+φ(m)(mod m)
其中c>=φ(m)。他很强,强到了一种逆天的程度。对于这个定理,我有一个优雅的证明,但是在网上打不出来。又及,c<φ(m)的时候直接快速幂。
回到这道题,这道题无非就是用扩展欧拉定理去解决它,虽然它的p在后面很恶心。
先把所有的东西读进来,处理好φ(p),再对指数进行类似于快读的处理。由于快读只涉及到加和乘,完全可以一边算一遍%φ(p)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<fstream> using namespace std; #define ll long long ll a,b,p,mod; char s[100005]; ll phi(int n){ ll ans=n; for(int i=2;i*i<=n;++i){ if(n%i==0){ ans=ans/i*(i-1); while(n%i==0)n/=i; } } if(n>1)ans=ans/n*(n-1); return ans; } long long KSM(ll a,ll b){ ll sp=1; while(b){ if(b&1)sp*=a; sp%=p; b>>=1; a=a*a; a%=p; } return sp; } int main(){ //freopen(".in","r",stdin); //freopen(".out","w",stdout); scanf("%lld%s%lld",&a,s,&p); int len=strlen(s); mod=phi(p); int flag=0; for(int i=0;i<len;++i){ b=b*10+(s[i]-'0'); if(b>=mod)flag=1; b%=mod; } if(flag)b+=mod; cout<<KSM(a,b)%p<<endl; return 0; }
降幂大法2
题面:
思路:
禁止套娃!!是的,看到省略号的时候我就直接懵了。你管这个叫题?分明就是俄罗斯套娃。
但是是套娃,又有答案,那他就不是无限套娃(世 界 崩 坏)。见过俄罗斯套娃的都知道,套娃必然会有一个最小的,此题个关键就在于找出最小的套娃。
由扩展欧拉定理可以知道,一个数膜另外一个数,这个任务可以甩给他的指数。指数又甩给它的指数,这就是套娃。于是这样我们可以设计一个函数,先令T=22...他的任务是解决T%p的问题,于是无限递归处理,然后p在不断地phi,phi,phi,phi...直到φ(p)=1,那么很显然的,一个数%1=0.套娃结束。最小的娃找到了
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<fstream> using namespace std; #define ll long long ll a,b,p; char s[100005]; ll phi(int n){ ll ans=n; for(int i=2;i*i<=n;++i){ if(n%i==0){ ans=ans/i*(i-1); while(n%i==0)n/=i; } } if(n>1)ans=ans/n*(n-1); return ans; } long long KSM(ll a,ll b,ll mod){ ll sp=1; while(b){ if(b&1)sp*=a; sp%=mod; b>>=1; a=a*a; a%=mod; } return sp; } int solve(int p){ int k=phi(p); if(k==1)return 0; return KSM(2,(solve(k)+k),p); } int main(){ while(scanf("%lld",&p)!=EOF){ cout<<solve(p)<<endl; } return 0; }