质数的判定
试除法判断
质数的筛选
暴力筛
ll get_prime(ll n)//暴力筛
{
ll i, j, cnt = 0, f;
for (i = 2; i <= n; i++)
{
f = 1;//假设i是素数
for (j = 2; j <= sqrt(i); j++)
//一个合数n的最小质因子一定小于等于根号n
{
if (i % j == 0)
{
f = 0;
break;
}
}
if (f)//若i是素数,放入prime数组
prime[cnt++] = i;//cnt计数器++
}
return cnt;//返回素数的个数
}
埃式筛
using ll = long long;
const ll N = 1e6;
bool isprime[N]; //布尔数组表示是否是素数****
ll prime[N]; //用来存放素数的数组
ll get_prime(ll n) //埃式筛
{
ll i, f, cnt = 0, j;
memset(isprime, 1, sizeof(isprime)); //先假设都是素数
isprime[0] = isprime[1] = 0; //0,1都不是素数
for (i = 2; i <= n; i++) //优化1:i判断到√n即可,此优化有风险,不建议
{
if (isprime[i]) //若是素数
{
prime[cnt++] = i;//放入素数数组
for (j = i * i; j <= n; j += i) //优化2:j从i开始更高效,i之前的已经被筛了,防止重复筛
isprime[j] = 0;//筛掉该素数因子的所有合数
}
}
return cnt; //返回素数的个数
}
欧拉筛
using ll = long long;
const ll N = 1e7;
int prime[N]; //素数数组
bool isprime[N];//表明是否是素数****
ll getprime(ll n)//欧拉筛
{
ll cnt = 0, i, j;
memset(isprime, 1, sizeof(isprime));//初始都是素数
isprime[0] = isprime[1] = 0;//0,1不是素数
for (i = 2; i < n; i++)
{//每次循环,倍数i会慢慢变大
if (isprime[i])//若是素数,则加入素数数组
prime[cnt++] = i;
for (j = 0; j < cnt && i * prime[j] < n; j++)//遍历每个素数
{//i是倍数,prime是素因子
isprime[i * prime[j]] = 0;//筛去prime的倍数的数
if (i % prime[j] == 0)//每个数只能让最大倍数*最小素因子数才能保证筛一次
break;
}
}
return cnt;//返回素数个数
}
牛客一道小栗子Prime Distance
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
const int N = 1e7 + 10;
const int M = 1e7 + 7;
const int inf = 0x3f3f3f3f;
const int eps = 1e-6;
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0)
int l, r, tot, cnt;
ll now[N], prime[N]; //注意这里开大啊,N=1e7+10
bool isprime[N], vis[N]; //
inline void get_prime() //线性筛
{
for (int i = 2; i < M; i++)
{
if (!isprime[i]) //后面没有{},这里0表示是素数,1表示不是素数
prime[++tot] = i;
for (int j = 1; j <= tot && i * prime[j] < M; j++) //是&&,不能用,
{
isprime[i * prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
int main()
{
// IOS;
get_prime();
while (~scanf("%d%d", &l, &r))
{
cnt = 0; //
memset(vis, 0, sizeof(vis));
for (ll i = 1; i <= tot && prime[i] * prime[i] <= r; i++) //对每个素数而言
{
ll x = prime[i]; //此处有【向上取整算法:向下取整(l+p-1)/p=向上取整(l/p)】
for (ll j = max(x * 2ll, (l + x - 1) / x * x); j <= r; j += x) //筛选出l~r之间的素数
vis[j - l] = 1; //应该从p*2开始,因为p*1的话p是素数,不能标记
}
for (ll i = 0; i <= r - l; i++)
{
if (l + i <= 1) //特判0,1
continue;
if (!vis[i])
now[++cnt] = i + l; //now是筛选出的素数的集合
}
if (cnt < 2)
printf("There are no adjacent primes.\n");
else
{
pii mi, ma;
int minn = inf, maxx = -inf;
for (int i = 1; i < cnt; i++) //注意有i+1,所以i<cnt而不是=
{
if (minn > now[i + 1] - now[i])
{
minn = now[i + 1] - now[i];
mi.first = now[i], mi.second = now[i + 1];
}
if (maxx < now[i + 1] - now[i]) //不能else
{
maxx = now[i + 1] - now[i];
ma.first = now[i], ma.second = now[i + 1];
}
}
printf("%d,%d are closest, %d,%d are most distant.\n", mi.first, mi.second, ma.first, ma.second);
}
}
return 0;
}
质因数分解
算术基本定理:任何一个大于1的正整数都能唯一分解为有限个质数的乘积即N=p1^c1* p2^c2 * … * pm^cm
推论1:N的正约数个数为(c1+1)* (c2+1) * … * (cm+1)
推论2:N的正约数的和为(1+p1+p12+…+p1c1)*…(1+pm+pm2+…+pmcm)
分解单个数字:
get_prime(n);//欧拉筛
for (int i = 1; i <= tot; i++)//枚举每个数组
{
if (n % prime[i] == 0)
{//first代表质因子,second代表质因子的次数
ans[++cnt].first = prime[i], ans[cnt].second = 0;
while (n % prime[i] == 0)
{
n /= prime[i];
ans[cnt].second++;
}
}
}
if (n > 1)//n是质数
ans[++cnt].first = n, ans[cnt].second = 1;
for (int i = 1; i <= cnt; i++)
cout << ans[i].first << ' ' << ans[i].second << endl
牛客一个小栗子阶乘分解
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
const int N = 1e6 + 10;
const int M = 1e7 + 7;
const int inf = 0x3f3f3f3f;
const int eps = 1e-6;
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0)
int n, tot, cnt;
bool noprime[N];
int prime[N];
pii ans[N];
inline void get_prime(int n) //欧拉筛
{
noprime[0] = noprime[1] = 1;
for (int i = 2; i <= n; i++) //
{
if (!noprime[i])
prime[++tot] = i;
for (int j = 1; j <= tot && i * prime[j] <= n; j++)
{
noprime[i * prime[j]] = 1;
if (!i % prime[j])
break;
}
}
}
inline ll fast_pow(int a, int b) //快速幂
{
ll res = 1;
for (; b; b >>= 1)
{
if (b & 1)
res *= a;
a *= a;
}
return res;
}
int main()
{
IOS;
cin >> n;
get_prime(n); //欧拉筛
for (int i = 1; i <= tot; i++) //枚举每个数组
{
ans[++cnt].first = prime[i]; //用到了log函数【log(n)/log(m)表示以m为底,n的对数】
for (int k = 1; k <= int(log(n) / log(prime[i])); k++)
ans[cnt].second += int(n / fast_pow(prime[i], k));
} //推导的结论【N!中质因子p的个数为Σ向下取整[N/(p^k)],其中1≤k≤log(N)/log(p)】
for (int i = 1; i <= cnt; i++)
cout << ans[i].first << ' ' << ans[i].second << endl;
return 0;
}