1. 程式人生 > 其它 >尤拉定理

尤拉定理

尤拉定理

尤拉定理

\(gcd(a,m)=1\) 時, \(a^{x}\equiv a^{x \mod \phi(m)}\;(mod\;m)\)

擴充套件尤拉定理:

\(a^{x}\equiv a^{x \mod \phi(m)+\phi(m)}\;(mod\;m)\)

證明:

a 與 m 互質時,從 \(a_0\) 就進入迴圈

a 與 m 不互質時,從前 c 項不進入迴圈,設迴圈長度為 L

設已經走了 x 步,則 x = L + x - L 所以先走 L 步進入迴圈,這時再走 x - L 步的位置與再走 (x - L) % L 一樣,因此有

​ (L + (x - L) % L) = L + x % L, 即 \(a^{x}\equiv a^{x \mod \phi(m)+\phi(m)}\;(mod\;m)\)

BZOJ 3884, 上帝與集合的正確用法 - 題目 - Daimayuan Online Judge

\(\phi (m)\) 的性質

  1. \(\phi(m)\) 為偶數(除 m = 2 外)

  2. \(\phi(m)<=\frac m2\)

因此只需 log p 次就可將 p 減為 1,因此只需遞迴子問題 log p 次即可

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;

ll qmi(ll a, ll b, ll p)
{
	ll ans = 1;
	while(b)
	{
		if (b & 1)
			ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans % p;
}
//遞迴子問題求解
ll calc(int p)
{
	if (p == 1)
		return 0;
	ll phip = p, now = p;
	for (int i = 2; i <= now / i; i++)
	{
		if (now % i) continue;
		phip = phip / i * (i - 1);
		while(now % i == 0) now /= i;
	}
	if (now > 1) phip = phip / now * (now - 1);
	ll ans = calc(phip);
	return qmi(2, ans + phip, p);
}
ll solve()
{
	int p;
	cin >> p;
	return calc(p);
}
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
		cout << solve() << endl;
	return 0;
}

CF Round #454(Div 1) D, Power Tower - 題目 - Daimayuan Online Judge

使用擴充套件尤拉定理降冪時,重定義 mod 運算為

ll mod(ll a, ll b)
{
	if (a < b) return a;
	return a % b + b;
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
map<ll, ll> mp;
//使用擴充套件尤拉定理時要重定義mod
ll mod(ll a, ll b)
{
	if (a < b) return a;
	return a % b + b;
}

ll qmi(ll a, ll b, ll p)
{
	ll ans = 1;
	while(b)
	{
		if (b & 1)
			ans = mod(ans * a, p);
		b >>= 1;
		a = mod(a * a, p);
	}
	return mod(ans, p);
}

ll phi(ll x)
{
	if (mp[x]) return mp[x];
	ll now = x, ans = x;
	for (int i = 2; i <= now / i; i++)
	{
		if (now % i == 0)
			ans -= ans / i;
		while(now % i == 0)
			now /= i;
	}
	if (now > 1)
		ans -= ans / now;
	return mp[x] = ans;
}

ll solve(int l, int r, int p)
{
	if (p == 1 || l == r) return mod(a[l], p);
	return qmi(a[l], solve(l+1, r, phi(p)), p);
}
int main()
{
	int n, m, q;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%lld", a + i);
	scanf("%d", &q);
	while(q--)
	{
		int l, r;
		scanf("%d%d", &l, &r);
		printf("%lld\n", solve(l, r, m) % m);
	}
		
	return 0;
}