P5091 【模板】擴展歐拉定理 題解

博客園同步

原題鏈接

前置知識:

歐拉篩,一些基本數論知識。

簡要題意:

ab%ma^b \% m.

1a109,1b102×107,1m1081 \leq a \leq 10^9 , 1 \leq b \leq 10^{2 \times 10^7} , 1 \leq m \leq 10^8.

首先,看到這個數據範圍你就發現你涼涼了。

算法一

一個簡單的弱化:

a,b,m107a,b,m \leq 10^7.

顯然你 O(b)\mathcal{O}(b) 過了。

算法二

一個再簡單點的強化呢:

. a,b,m1018a,b,m \leq 10^{18}.

你用 O(logb)\mathcal{O}(\log b) 可以飛快過了 。

算法三

那麼考慮這道題目呢?不行了吧?

可能,O(logb)\mathcal{O}(\log b) 的樸素快速冪 ++ 每次 bb 的高精度除法 ÷2\div2 ++ 一定卡常是可以通過的。

但是我們不要,我們只需要用一個簡單的定理:

ab{ab                     ,b<ϕ(m)ab mod ϕ(m)+ϕ(m),bϕ(m)a^b \equiv \begin{cases} a^b \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space \space, b < \phi(m) \\ a^{b \space \text{mod} \space \phi(m) + \phi(m)} , b \geq \phi(m) \\ \end{cases}

先不管如何證明,考慮用這個玩意兒怎麼做。

O(m)\mathcal{O}(\sqrt{m}) 的時間可以算出 ϕ(m)\phi(m),然後快讀 bbbϕ(m)b \leq \phi(m) 則套公式快速冪,如果 b<ϕ(m)b < \phi(m) 只能說明 bb 也很小,再跑一個 log\log 也沒啥問題了。

具體證明大家可以去看一下 ouuan\text{ouuan} 的博客

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

#define int long long

inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}

inline int remo(int m) {
	char c; while(!isdigit(c=getchar()));
	int x=0; bool f=0;
	for(;isdigit(c);c=getchar()) {
		x=x*10+c-'0';
		if(x>=m) f=1,x%=m;
	} return f?(x+m):x;
}

inline void write(int x) {
	if(x<0) {putchar('-');write(-x);return;}
	if(x<10) {putchar(char(x%10+'0'));return;}
	write(x/10);putchar(char(x%10+'0'));
}

inline int pw(int a,int b,int m) {
	int ans=1; while(b) {
		if(b&1) ans=ans*a%m;
		a=a*a%m; b>>=1;
	} return ans;
}

signed main() {
	int a=read(),m=read(); a%=m;
	int phi=1,t=m,ans=1; 
	for(int i=2;i*i<=t;i++) {
		if(t%i) continue;
		phi*=i-1; t/=i;
		while(t%i==0) phi*=i,t/=i;
	} if(t>1) phi*=t-1; //printf("%d\n",remo(phi));
	printf("%d\n",pw(a,remo(phi),m));
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章