1.素数判定
1.1试除法判素数
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
return false;
return true;
}
1.2 Miller−Rabin 判定法
ll Rand() {//决定了程序的性能
static ll x = (srand((int)time(0)), rand());
x += 1000003;
if (x > 1000000007)
x -= 1000000007;
return x;
}
bool Witness(ll a, ll n) {
ll t = 0, u = n - 1;
while (!(u & 1))
u >>= 1, t++;
ll x = qpow(a, u, n), y;//qpow为快速幂
while (t--) {
y = x * x % n;
if (y == 1 && x != 1 && x != n - 1)
return true;
x = y;
}
return x != 1;
}
bool MillerRabin(ll n, ll s) {
if (n == 2 || n == 3 || n == 5)
return 1;
if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n == 1)
return 0;
while (s--) {
if (Witness(Rand() % (n - 1) + 1, n))
return false;
}
return true;
}
1.3埃氏筛
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (st[i]) continue;
primes[cnt ++ ] = i;
for (int j = i + i; j <= n; j += i)
st[j] = true;
}
}
1.4线性筛
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
2.质因数分解
2.1试除法分解
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;
cout << i << ' ' << s << endl;
}
if (x > 1) cout << x << ' ' << 1 << endl;
cout << endl;
}
2.2 Pollard Rho 算法
见到的几种实现:
1-----------------------
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
using namespace std;
const int N = 1e5 + 7;
ll x, y, a[N];
ll max_factor;
struct BigIntegerFactor {
const static int N = 1e6 + 7;
const static ll inf=0x3f3f3f3f3f3f3f3f;
ll prime[N], p[N], fac[N], sz, cnt; //多组输入注意初始化cnt = 0
inline ll mul(ll a, ll b, ll mod) { //WA了尝试改为__int128或慢速乘
if (mod <= 1000000000)
return a * b % mod;
return (a * b - (ll)((long double)a / mod * b + 1e-8) * mod + mod) % mod;
}
void init(int maxn) //线性筛
{
int tot = 0;
sz = maxn - 1;
for (int i = 1; i <= sz; ++i)
p[i] = i;
for (int i = 2; i <= sz; ++i) {
if (p[i] == i)
prime[tot++] = i;
for (int j = 0; j < tot && 1ll * i * prime[j] <= sz; ++j) {
p[i * prime[j]] = prime[j];
if (i % prime[j] == 0)
break;
}
}
}
ll qpow(ll a, ll x, ll mod)
{
ll res = 1ll;
while (x) {
if (x & 1)
res = mul(res, a, mod);
a = mul(a, a, mod);
x >>= 1;
}
return res;
}
bool check(ll a, ll n) { //二次探测原理检验n
ll t = 0, u = n - 1;
while (!(u & 1))
t++, u >>= 1;
ll x = qpow(a, u, n), xx = 0;
while (t--) {
xx = mul(x, x, n);
if (xx == 1 && x != 1 && x != n - 1)
return false;
x = xx;
}
return xx == 1;
}
bool miller(ll n, int k) {
if (n == 2)
return true;
if (n < 2 || !(n & 1))
return false;
if (n <= sz)
return p[n] == n;
for (int i = 0; i <= k; ++i) { //测试k次
if (!check(rand() % (n - 1) + 1, n))
return false;
}
return true;
}
inline ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
inline ll Abs(ll x) {
return x < 0 ? -x : x;
}
ll Pollard_rho(ll n) { //基于路径倍增的Pollard_Rho算法
ll s = 0, t = 0, c = rand() % (n - 1) + 1, v = 1, ed = 1;
while (1) {
for (int i = 1; i <= ed; ++i) {
t = (mul(t, t, n) + c) % n;
v = mul(v, Abs(t - s), n);
if (i % 127 == 0) {
ll d = gcd(v, n);
if (d > 1)
return d;
}
}
ll d = gcd(v, n);
if (d > 1)
return d;
s = t;
v = 1;
ed <<= 1;
}
}
void getfactor(ll n) { //得到所有的质因子(可能有重复的)
if (n <= sz) {
while (n != 1)
fac[cnt ++ ] = p[n], n /= p[n];
max_factor = max_factor > p[n] ? max_factor : p[n];
return;
}
if (miller(n, 6)) {
fac[cnt ++ ] = n;
max_factor = max_factor > n ? max_factor : n;
}
else {
ll d = n;
while (d >= n)
d = Pollard_rho(n);
getfactor(d);
getfactor(n / d);
}
return ;
}
ll cal(ll n,ll p){
ll ans=0;
while(n)
{
ans+=n/p;
n/=p;
}
return ans;
}
ll slove(ll n,ll x,ll y){
cnt=0;
map<ll,ll> mm;
getfactor(x);
ll ans=inf;
for(int i;i<cnt;i++)
{
mm[fac[i]]++;
}
for(auto it:mm)
{
ll num=0;
for(int i=0;i<n;i++)
{
num+=cal(a[i],it.fi);
}
ans=min(ans,(cal(y,it.fi)-num)/it.se);
}
return ans;
}
}Q;
int main()
{
//Q.init(N - 1);//如果代码超时且仅需要分解大数的质因数可以用这句话,否则不要用
ll t;
scanf("%lld",&t);
while(t--)
{
}
}
2-----------------------------------------
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
const ll mod = 998244353;
unordered_map <ll, ll> mp;
namespace rho{
const int MAXP = 1000010;
const int BASE[] = {2, 450775, 1795265022, 9780504, 28178, 9375, 325};
long long seq[MAXP];
int primes[MAXP], spf[MAXP];
long long gcd(long long a, long long b) {
int ret = 0;
while(a) {
for( ; !(a & 1) && !(b & 1); ++ret, a >>= 1, b >>= 1);
for( ; !(a & 1); a >>= 1);
for( ; !(b & 1); b >>= 1);
if(a < b) swap(a, b);
a -= b;
}
return b << ret;
}
inline long long mod_add(long long x, long long y, long long m){
return (x += y) < m ? x : x - m;
}
inline long long mod_mul(long long x, long long y, long long m){
long long res = x * y - (long long)((long double)x * y / m + 0.5) * m;
return res < 0 ? res + m : res;
}
inline long long mod_pow(long long x, long long n, long long m){
long long res = 1 % m;
for (; n; n >>= 1){
if (n & 1) res = mod_mul(res, x, m);
x = mod_mul(x, x, m);
}
return res;
}
inline bool miller_rabin(long long n){
if (n <= 2 || (n & 1 ^ 1)) return (n == 2);
if (n < MAXP) return spf[n] == n;
long long c, d, s = 0, r = n - 1;
for (; !(r & 1); r >>= 1, s++) {}
for (int i = 0; primes[i] < n && primes[i] < 32; i++){
c = mod_pow(primes[i], r, n);
for (int j = 0; j < s; j++){
d = mod_mul(c, c, n);
if (d == 1 && c != 1 && c != (n - 1)) return false;
c = d;
}
if (c != 1) return false;
}
return true;
}
inline void init(){
int i, j, k, cnt = 0;
for (i = 2; i < MAXP; i++){
if (!spf[i]) primes[cnt++] = spf[i] = i;
for (j = 0, k; (k = i * primes[j]) < MAXP; j++){
spf[k] = primes[j];
if(spf[i] == spf[k]) break;
}
}
}
long long pollard_rho(long long n){
while (1){
long long x = rand() % n, y = x, c = rand() % n, u = 1, v, t = 0;
long long *px = seq, *py = seq;
while (1){
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
if((x = *px++) == y) break;
v = u;
u = mod_mul(u, abs(y - x), n);
if (!u) return gcd(v, n);
if (++t == 32){
t = 0;
if ((u = gcd(u, n)) > 1 && u < n) return u;
}
}
if (t && (u = gcd(u, n)) > 1 && u < n) return u;
}
}
vector <long long> factorize(long long n){
if (n == 1) return vector <long long>();
if (miller_rabin(n)) return vector<long long> {n};
vector <long long> v, w;
while (n > 1 && n < MAXP){
v.push_back(spf[n]);
n /= spf[n];
}
if (n >= MAXP) {
long long x = pollard_rho(n);
v = factorize(x);
w = factorize(n / x);
v.insert(v.end(), w.begin(), w.end());
}
sort(v.begin(), v.end());
return v;
}
}
signed main() {
// Q.init(N - 1);//如果代码超时且仅需要分解大数的质因数可以用这句话,否则不要用
ll T, n;
rho :: init();
scanf("%lld", &T);
while (T--) {
scanf("%lld", &n);
vector <ll> res = rho :: factorize(n);
for(auto it : res)
mp[it] ++ ;
}
ll ans = 1;
for(auto it : mp)
ans = (ans * (it.second + 1)) % mod;
printf("%lld\n", ans);
return 0;
}
3----这个是最快的(T了可以试试,比2快了有一倍)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxp = 1e6 + 1, maxv = 25, maxc = (int)1e4 + 1;
int ptot, pr[maxp], d[maxp], cnt;
LL n, p[maxc];
LL mod_add(LL x, LL y, LL p) {
return (x += y) < p ? x : x - p;
}
LL mod_mul(LL x, LL y, LL p) {
LL ret = x * y - (LL)((long double)x * y / p + 0.5) * p;
return ret < 0 ? ret + p : ret;
}
LL mod_pow(LL x, LL k, LL p) {
LL ret = 1 % p;
for( ; k > 0; k >>= 1, x = mod_mul(x, x, p))
(k & 1) && (ret = mod_mul(ret, x, p));
return ret;
}
bool miller_rabin(LL n) {
if(n == 2) return 1;
if(n < 2 || !(n & 1))
return 0;
LL s = 0, r = n - 1;
for( ; !(r & 1); r >>= 1, ++s);
for(int i = 0; pr[i] < n && pr[i] < maxv; ++i) {
LL cur = mod_pow(pr[i], r, n), nxt;
for(int j = 0; j < s; ++j) {
nxt = mod_mul(cur, cur, n);
if(nxt == 1 && cur != 1 && cur != n - 1) return 0;
cur = nxt;
}
if(cur != 1) return 0;
}
return 1;
}
LL gcd(LL a, LL b) {
int ret = 0;
while(a) {
for( ; !(a & 1) && !(b & 1); ++ret, a >>= 1, b >>= 1);
for( ; !(a & 1); a >>= 1);
for( ; !(b & 1); b >>= 1);
if(a < b)
swap(a, b);
a -= b;
}
return b << ret;
}
LL pollard_rho(LL n) {
static LL seq[maxp];
while(1) {
LL x = rand() % n, y = x, c = rand() % n;
LL *px = seq, *py = seq, tim = 0, prd = 1;
while(1) {
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
*py++ = y = mod_add(mod_mul(y, y, n), c, n);
if((x = *px++) == y) break;
LL tmp = prd;
prd = mod_mul(prd, abs(y - x), n);
if(!prd) return gcd(tmp, n);
if((++tim) == maxv) {
if((prd = gcd(prd, n)) > 1 && prd < n) return prd;
tim = 0;
}
}
if(tim && (prd = gcd(prd, n)) > 1 && prd < n) return prd;
}
}
void decompose(LL n) {
for(int i = 0; i < cnt; ++i)
if(n % p[i] == 0) {
p[cnt++] = p[i];
n /= p[i];
}
if(n < maxp) {
for( ; n > 1; p[cnt++] = d[n], n /= d[n]);
} else if(miller_rabin(n)) {
p[cnt++] = n;
} else {
LL fact = pollard_rho(n);
decompose(fact), decompose(n / fact);
}
} // prepare pr(prime) and d(minimal factor)
int main() {
for(int i = 2; i < maxp; ++i) {
if(!d[i])
pr[ptot++] = d[i] = i;
for(int j = 0, k; (k = i * pr[j]) < maxp; ++j) {
d[k] = pr[j];
if(d[i] == pr[j])
break;
}
}
int m, mod = 998244353;
scanf("%d", &m);
while(m--) {
scanf("%lld", &n);
decompose(n);
}
sort(p, p + cnt);
int ans = 1;
for(int i = 0; i < cnt; ) {
int ctr = 0;
for(LL pp = p[i]; i < cnt && p[i] == pp; ++i, ++ctr);
ans = ans * (ctr + 1LL) % mod;
}
printf("%d\n", ans);
return 0;
}
3.因数
3.1 试除法找因数
vector<int> get_divisors(int x)
{
vector<int> res;
for (int i = 1; i <= x / i; i ++ )
if (x % i == 0)
{
res.push_back(i);
if (i != x / i) res.push_back(x / i);
}
sort(res.begin(), res.end());
return res;
}
3.2枚举倍数找因数(常用于一些于因子有关的计算,通过枚举倍数nlogn求解)
for(int i = 1; i <= n; ++ i){
for(int j = 1 ;j * i <= n; ++ j){
factor[i * j].push_back(j);
}
}
for(int i = 1; i <= n; ++ i){
cout << i << ": ";
for(int j = 0; j < factor[i].size(); ++ j)
printf("%d ", factor[i][j]);
puts("");
}
3.3 一些性质
如果 N = p1^c1 * p2^c2 * … *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * … * (ck + 1)
约数之和: (p1^0 + p1^1 + … + p1^c1) * … * (pk^0 + pk^1 + …+ pk^ck)
3.4 最大公约数,最小公倍数
4.欧拉函数
4.1按定义求
int phi(int x)
{
int res = x;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
4.2 筛法求欧拉函数
int primes[N], cnt; // primes[]存储所有素数
int euler[N]; // 存储每个数的欧拉函数
bool st[N]; // st[x]存储x是否被筛掉
void get_eulers(int n)
{
euler[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ )
{
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0)
{
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
}
5.同余
5.1快速幂
int qmi(int m, int k, int p)
{
int res = 1 % p, t = m;
while (k)
{
if (k&1) res = res * t % p;
t = t * t % p;
k >>= 1;
}
return res;
}
5.2龟速乘
ll Mul(ll a, ll b, ll p)
{
if(b < 0) a = - a, b = - b;
ll res = 0;//因为是加法模拟乘法,所以res开始为0
while(b) {
if(b & 1) res = (res + a) % p;
a = (a + a) % p;
b >>= 1;
}
return res;
}
5.3 欧拉定理
5.4 费马小定理
5.5 威尔逊定理
6.拓展欧几里得
6.1 拓展欧几里得算法
// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
if (!b)
{
x = 1; y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= (a/b) * x;
return d;
}
- 逆元
7.1费马小定理求逆元
int inv(int x,int p) {return qpow(x, mod - 2, p) % p;}
7.2拓展欧几里得求逆元
int inv(int a,int mod)
{
int x,y;
exgcd(a,mod,x,y);
return (x % mod + mod) % mod;
}
7.3线性递推求逆元
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}
7.4求阶乘逆元
8.线性同余
9.高次同余方程
9.1 bsgs与exbsgs算法模板
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+7;
const int mod=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll hs[N], head[N], nexts[N], id[N], top;
void insert(ll x, ll y, ll mod) //mod传 N
{
ll k = x % mod;
hs[top] = x;
id[top] = y;
nexts[top] = head[k];
head[k] = top++;
}
ll find(ll x, ll mod)
{
ll k = x % mod;
for (int i = head[k]; i != -1; i = nexts[i])
if (hs[i] == x)
return id[i];
return -1;
}
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll BSGS(ll a, ll b, ll p, ll a1) //质数传1
{
memset(head, -1, sizeof(head));
top = 1;
a %= p, b %= p;
if (a1 == 1 && 1 % p == b % p)
return 0;
if (a == 0)
{
if (b == 0)
return 1;
else
return -1;
}
//unordered_map<ll, ll> hash; //map unordered_map 都试试
ll k = sqrt(p) + 1;
ll ak = 1;
for (ll i = 0; i < k; ++i)
{
ll t = ak * b % p;
insert(t, i, N);
//hash[t] = i;
ak = ak * a % p;
}
for (ll i = 0; i <= k; ++i)
{
/* if (hash.count(a1) && i * k - hash[a1] >= 0)
return i * k - hash[a1]; */
ll j = find(a1, N);
if (j != -1 && i * k - j >= 0)
return i * k - j;
a1 = a1 * ak % p;
}
return -1;
}
ll exBSGS(ll a, ll b, ll p)
{
a %= p, b %= p;
if (b == 1 || p == 1)
return 0;
ll cnt = 0, a1 = 1;
ll d = gcd(a, p);
while (d > 1)
{
if (b % d)
return -1;
p /= d;
b /= d;
a1 = (a1 * a / d) % p;
++cnt;
if (b == a1)
return cnt;
d = gcd(a, p);
}
ll res = BSGS(a, b, p, a1);
if (res == -1)
return -1;
else
return res + cnt;
}