数论
https://www.zybuluo.com/wzq/note/454095
1.最大公约数gcd(辗转相除法:)
gcd(10,4)=gcd(4,2)=gcd(2,0)=2
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
2.最小公倍数lcm
lcm(10,4)=10/2*4=20;
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
3.埃拉托斯特尼筛法
(在10^7内可以很快的算出)复杂度(0(n))
从2开始 筛选 ,当该数字为质数时,就将后面该质数的倍数删掉,但这种方法会重复删一些数(2–>6, 3–>6).
const int maxn=(1e7)+5;
int Prime[maxn];
void Prepare_Prime()
{
static bool isPrime[maxn];
memset(isPrime,true,sizeof(isPrime));
Prime[0]=0;//记录有多少个质数
for(int i=2;i<maxn; i++)
if(isPrime[i])
{
Prime[++prime[0]]=i;//储存质数
for(int j=i+i; j<maxn; j+=i) isPrime[j]=false;//删除该质数的倍数
}
printf("%d\n",Prime[0]);
}
4.欧拉筛选法 复杂度o(log n)
从2开始筛选 ,将筛选出的质数存入数组中, 将是质数倍数的数删除,当与质数相乘的数是指数的倍数,停止删除。
2 3 4 5 6 7 8 9 10 11 12
质数:2 3
2 4
3 6 9
4 8
5 10
const int maxn=1e7+100;
int fp[maxn],pr[maxn],phi[maxn] //fp[i]表示i的最小质因子,pr[0]表示质数的个数,pr[i]是质数数组,phi[i]是i的欧拉函数
void ola_prime(int n)
{
memset(fp,0,sizeof(fp));
pr[0]=0;
for(int i=2; i<=n; i++)
{
if(!fp[i])
{
pr[++pr[0]]=i;fp[i]=i;phi[i]=i-1;
}
for(int j=1; j<=pr[0]; j++)
{
int k=i*pr[j];
if(k>n) break;
fp[k]=pr[j];
if(k%pr[j]==0)
{
phi[k]=phi[i]*pr[j];
break;
}
else phi[k]=phi[i]*(pr[j]-1);
}
}
}
5.质因数分解
一个正数n,最多只有一个大于根号n的质因数,因此,枚举根号n以内的质数分解质因数。当最后的数不为1时,说明还有一个质数为n.
struct P_factor
{
int p, k;
P_factor() {p=k=0};
p_factor(int a,int b)
{
p=a;k=b;
}
};
vector<P_factor> divide_factor(int x)
{
vector<P_factor> R;
R.clear();
for(int i=1; i<=Prime[0]; i++)//Prime[]为2-->sqrt(x)的质数数组
{
int p=Prime[i];
if(p*p>x) break;
if(x%p==0)
{
int k=0;
while(x%p==0) k++,x/=p;
R.push_back(P_factor(p,k));
}
}
if(x>1) R.push_back(P_factor(x,1));
return 0;
}
质因数分解形式下的gcd和lcm
a = p1^k1 * p2^k2 … pm^km (ki>0)
b = p1^r1 * p2^r2 … pm^rm (ri>0)
gcd(a,b) = p1^min(k1,r1) * p2^min(k2,r2)… pm^min(km,rm)
lcm(a,b) = p1^max(k1,r1) * p2^max(k2,r2)… pm^max(km,rm)
例如:
100 = 2^2 * 5^2
40 =2^2 * 2^1 * 5^1
gcd(100,40) = 2^2 * 2^0 * 5^1=20
lcm(100,40) = 2^2 * 2^1 * 5^2 =200