Pollard-Rho

Miller-Rabin

大素数测试

Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小。出错的概率到底是多少,存在严格的理论推导。

费马小定理

(p) 是素数, (gcd(a,p) = 1) , 那么 (a^{p-1} = 1 (mod p))

如果存在 $a < p $ , 且 (a^{p-1} \% p e 1) , 则 (p) 肯定不是素数

有限域上的平方根定理

如果 (p) 是一个奇素数且 (e ge 1) ,则

[x^2 = 1 (mod p^e) ]

仅有两个根 (x = 1)(x = -1) , 注意到在模 (p) 的意义下 (x = -1) 等价于 (x = p - 1) , 正负一 也被称为 (1) 的平凡平方根

如果对模 (n) 存在 (1) 的非平凡平方根, (n) 一定是合数

...

没有很懂

抄了个板子,A 了 19徐州那道题

E- Multiply

但是只过了洛谷的板子的两个点

【模板】Pollard-Rho

还顺带把 CCPC威海的 D 题给 AC了

(判断有没有一个质因数的次数大于等于2)

signed main(){
    scanf("%lld",&T);
    while(T--){
        ans = 0;
        scanf("%lld",&n);m.clear();
        find(n);
        if(ans)puts("yes");
        else puts("no");
        
    }
}

这个板子用着应该是没啥问题

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;

int x[105];
int mul(int a, int b, int p){
	int ans = 0;
	while (b){
		if (b & 1LL) ans = (ans + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return ans;
}

int qpow(int a, int b, int p){
	int ans = 1;
	while (b){
		if (b & 1LL) ans = mul(ans, a, p);
		a = mul(a, a, p);
		b >>= 1;
	}
	return ans;
}

bool Miller_Rabin(int n){ //大素数测试
	if (n == 2) return true;
	int s = 20, i, t = 0;
	int u = n - 1;
	while (!(u & 1))
	{
		t++;
		u >>= 1;
	}
	while (s--)
	{
		int a = rand() % (n - 2) + 2;
		x[0] = qpow(a, u, n);
		for (i = 1; i <= t; i++)
		{
			x[i] = mul(x[i - 1], x[i - 1], n);
			if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1)
				return false;
		}
		if (x[t] != 1) return false;
	}
	return true;
}

int gcd(int a, int b){
	return b ? gcd(b, a % b) : a;
}

int Pollard_Rho(int n, int c){
	int i = 1, k = 2, x = rand() % (n - 1) + 1, y = x;
	while (1){
		i++;
		x = (mul(x, x, n) + c) % n;
		int p = gcd((y - x + n) % n, n);
		if (p != 1 && p != n) return p;
		if (y == x) return n;
		if (i == k){
			y = x;
			k <<= 1;
		}
	}
}

map<int, int> m;
void find(int n, int c = 12345)
{
	if (n == 1) return;
	if (Miller_Rabin(n)){
		m[n]++;
		return;
	}
	int p = n, k = c;
	while (p >= n) p = Pollard_Rho(p, c--);
	find(p, k);
	find(n / p, k);
}

E - Multiply

直接上板子

int T, n, X, Y, A[100010];

int cal(int n, int p) {
	int ans = 0;
	while (n) {
		ans += n / p;
		n /= p;
	}
	return ans;
}

map<int, int>mp;
signed main() {
	scanf("%lld", &T);
	while (T--) {
		scanf("%lld%lld%lld", &n, &X, &Y);
		for (int i = 1; i <= n; i++)scanf("%lld", A + i);
		m.clear(); mp.clear();
		find(X);

		for (auto& i : m) {
			mp[i.first] += cal(Y, i.first);
		}
		for (auto& i : m) {
			for (int j = 1; j <= n; j++) {
				mp[i.first] -= cal(A[j], i.first);
			}
		}
		int ans = 1e18;

		for (auto& i : m) {
			ans = min(ans, mp[i.first] / i.second);
		}
		printf("%lld
", ans);

	}
}


原文地址:https://www.cnblogs.com/sduwh/p/13925242.html