数论基础
作者:互联网
最大公因数(gcd)
辗转相除法
运算速度: O(n)
计算公式:gcd(a,b) = gcd(b,a mod b)
代码:
int gcd(int a,int b)
{
int c=a%b;
while(c!=0)
{
a=b;
b=c;
c=a%b;
}
return b;
}
最小公倍数(lcm)
最小公倍数可以通过最大公约数求:最小公倍数 = 两数之和 / 最大公约数。
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
素数
欧拉线性素数筛
原理
基本思想 :
在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
关键:
if(i%prime[j]==0)break;
理解:
- 当 i是prime[j]的倍数时,i = k × prime[j],
- 如果继续运算 j+1,
-
- i × prime[j + 1] = prime[j] × k × prime[j+1]
- 这里prime[j]是最小的素因子,当i = k × prime[j+1]时会重复,
- 所以跳出循环。
举个例子 :
- i = 8 ,j = 1,prime[j] = 2,
如果不跳出循环,
- prime[j+1] = 3, 8 * 3 = 2 * 4 * 3 = 2 * 12,
在i = 12时会计算。
代码
bool visited[100100];//初始化
long long prime[100100];//保存素数
int cnt;
void Euler_prime()
{
memset(visited, true,sizeof (visited) );
visited[1]=false;
for(int i=2;i<100100;i++)
{
if(visited[i]) prime[cnt++]=i;
for(int j=0;j<cnt&&i*prime[j]<100100;j++)
{
visited[i*prime[j]] = false;
if(i%prime[j]==0)//关键
break;
}
}
}
实战
试除法判断素数
复杂度:O( \(\sqrt n\) )
原理:约数成对出现(完全平方数除外)
代码:
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,N]中素数的个数约为NlgN。
则从[1,N]中人选一个数,其为质数的概率为1/lgN。
算数基本定理
任意一个整数都能被分解为如下形式:
\(n=p^{k_{1}}_{1}×p^{k_{2}}_{2}×....×p^{k_{t}}_{t}\)。 其中p为质数。
约数
求是X的约数的个数
题意: 共有 N 个整数 A1,A2,…,AN,对于每一个数 Ai,求其他的数中有多少个是它的约数。
思路: 对于每个数判断其他数是不是他的倍数。
1291. 轻拍牛头
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f3f;
int n;
int a[N];
int cnt[N],st[N];
void slove()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
st[a[i]]++;
}
for(int i=1;i<=N;i++){
if(!st[i]) continue;
cnt[i]+=st[i]-1;
for(int j=i+i;j<=N;j+=i){
if(st[j])
cnt[j]+=st[i];
}
}
for(int i=1;i<=n;i++){
cout<<cnt[a[i]]<<endl;
}
}
signed main()
{
// int t;
// cin >> t;
// while (t--)
slove();
return 0;
}
标签:prime,约数,return,gcd,数论,基础,int,素数 来源: https://www.cnblogs.com/kingwz/p/15247937.html