1. 程式人生 > >計蒜客 Exponial (尤拉降冪)

計蒜客 Exponial (尤拉降冪)

題目連結

題意:給出一個n(1~1e9),m(1~1e9),求exponial(n)%m的值

解法:有這樣一個尤拉降冪的公式

         \left\{\begin{matrix} A^{B}mod (C)=A^{Bmod(phi(C))}modC& (B<phi(C)) \\ A^{B}mod (C)=A^{Bmod(phi(C))+phi(C)}modC& (B>=phi(C)) \end{matrix}\right.

          (phi(x)表示x的尤拉值)

          從n向1來DFS,在中間求冪時使用快速冪取膜然後就可以算出答案了~

尤拉函式:

                      對一個正整數N,尤拉函式是小於N且與N互質的數的個數.。

                      例如φ(24)=8,因為1, 5, 7, 11, 13, 17, 19, 23均和 24 互質。

                      φ(n) = n*(1-\frac{1}{p1})*(1-\frac{1}{p2})*....*(1-\frac{1}{pn})

  其中(p1.....pn)為N的素因子.

                       φ(24)=24*(1-\frac{1}{2})*(1-\frac{1}{3})=8.

程式碼如下

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 500;
#define inf 0x3f3f3f3f
#define ll long long
ll biao[] = { 0,1,2,9,(1 << 18) };//題目給出的式子的n<=4的結果值
ll mod_pow(ll a, ll n, ll mod) {//快速冪
	a %= mod;
	ll ret = 1;
	while (n) {
		if (n & 1) ret = (ret*a) % mod;
		a = a*a%mod;
		n >>= 1;
	}
	return ret;
}
ll euler(ll n) { //log(n)時間內求一個數的尤拉值
	ll ans = n;
	for (ll i = 2; i*i <= n; i++) {
		if (n%i == 0)
		{
			ans -= ans / i;
			while (n%i == 0) n /= i;
		}
	}
	if (n>1) ans -= ans / n;
	return ans;
}
ll dfs(ll n, ll m) {
	if (m == 1) return 1;
	if (n <= 4)    //因為當n<=4時才有可能出現冪小於等於模數的情況,其餘時候都是冪大於模數
	{              //所以預處理出n的最小4項結果,第5項已經遠大於模數的最大值1e9了
		if (biao[n] >= m) return biao[n] % m + m;
		return biao[n];
	}
	ll exp = dfs(n - 1, euler(m));
	return mod_pow(n, exp, m) + m;
}
int main() {
	ll n, mod;
	while (~scanf("%lld%lld", &n, &mod)) {
		ll exp = dfs(n - 1, euler(mod));
		ll ans = mod_pow(n, exp, mod);
		printf("%lld\n", ans);
	}
}