欧拉降幂公式
这里是大佬对欧拉降幂公式的证明,找了好久找到了一个看上去比较人性化的,但是还是看不懂,如果日后有兴趣 再回过头来看一下吧
https://blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/86742254
欧拉定理
欧拉降幂公式
用公式简单的表示为:
也就是说如果对于求解 ,因为b太大了不能使用快速幂,这时候就可以通过欧拉降幂,实现对b的不断更新,能将b控制在 的范围,从而再用快速幂解决这一类问题
例题1
FZU1759
属于模板题
b范围太大所以需要读入字符串类型,然后用欧拉降幂进行处理
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=2e6+7;
const int INF=1e9;
const ll INFF=1e18;
char s[maxn];
ll a,mod;
ll qpow(ll a,ll b,ll mod)//快速幂板子
{
ll res=1;
while(b)
{
if (b&1)res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
ll phi(ll n)//欧拉函数板子
{
ll res=n;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
res=res/i*(i-1);
while(n%i==0)n/=i;
}
}
if (n>1)res=res/n*(n-1);
return res;
}
int main()
{
while(~scanf("%lld%s%lld",&a,s,&mod))
{
ll l=strlen(s);
ll p=phi(mod);
ll b=0;
repp(i,0,l)
{
ll newb=b*10+s[i]-'0';
if (newb>=p)b=newb%p+p;
else b=newb;
}
WW(qpow(a,b,mod));
}
return 0;
}
例题2
这题画重点
对于初学的我还是太难了,这个递推式竟然没有手动去推出来…
Gym - 101550E - Exponial
我的思路:题意很简单清晰,但是实现起来一直想不到优化的方法,只能想到O(n)的欧拉降幂,从上面往下降,直到降到
,显然超时
当n=5的时候数值就已经大到10的几万次,也就是说当n>5的时候是肯定可以用欧拉降幂的
对应的公式的,然后就一直想不出来怎么简化时间了
大神思路:现在给定n,m
设所求式子为
;
由欧拉降幂可以得到递推式:
接下来我们显然是要求
,注意到细节,这里的模数已经发生了变化,我本来一直天真的因为模数是不变的,早知道写一下就很容易看出来了
同理:
…
什么时候可以退出呢?
首先可以观察到模数mod在不断的变小,直到变到1的时候就可以return了,因为任何数
都=0
其次,当n<=4的时候,数字都是可以很容易算出来的,那么也可以特判一下直接return,至于不return会不会超时我也不知道
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=2e6+7;
const int INF=1e9;
const ll INFF=1e18;
ll ans;
ll phi(ll n)
{
ll res=n;
for (int i=2; i*i<=n; i++)
{
if (n%i==0)
{
res=res/i*(i-1);
while(n%i==0)
n/=i;
}
}
if (n>1)
res=res/n*(n-1);
return res;
}
ll qpow(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if (b&1)
res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
ll solve(ll n,ll mod)
{
if (mod==1)return 0;
else if (n==1){return (1%mod);}
else if (n==2){return (2%mod);}
else if (n==3){return (9%mod);}
else if (n==4){return (qpow(4,9,mod));}
else
{
ll p=phi(mod);
return qpow(n,solve(n-1,p)+p,mod);
}
}
int main()
{
ll n,mod;
scanf("%lld%lld",&n,&mod);
WW(solve(n,mod));
return 0;
}