除法和模运算
a%b=a-a/b*b 其中a/b是整数除法
约数和倍数
如果两个数字a,b,满足a%b=0,那么我们就说a是b的倍数,b是a的约数,记作b|a 通常情况下只考虑正约数和正倍数
求约数
求数字n的所有约数:
1:O(n):从1枚举 n%i==0
2:O(n^0.5):约数总是成对出现,如果有a/b=c,就一定会有a/c=b,就可以只枚举到n^0.5就可以
int cnt, fac[N];//约数个数和约数 for(int i = 1; i * i <= n; i ++){//不要使用sqrt if(n % i == 0){ cnt ++; fac[cnt] = i; if(i * i != n){ cnt ++; fac[cnt] = n / i; } } }
求倍数
一个数字的倍数有无穷多个,所以通常只求出n以内的a的所有倍数
对于一个数字a,倍数一定是a,2a...n/a*a,所以可以枚举每次加a
质数判定与质约数
质数,也叫素数。如果一个数字的约数只有1和它本身,则这个数就是质数。如果一个数的约数超过两个,则为合数。
1既不是质数也不是合数
质约数:既是一个数的约数同时本身也是一个质数
判定一个数是否是质数
int ans = 1;//为1表示是质数,为0表示不是质数 for(int i = 2; i * i <=n; i ++){//注意从2开始 if(n % i == 0 ){ ans = 0; break ; } }
算数基本定理:
任何一个大于1的自然数N,如果N不是质数,都可以唯一分解成有限个质数,即N=(P1^a1)*(p2^a2)....*(pn^an)
p1<p2<...<pn,P都是质数,a都是正整数
这个定理在数论中非常重要。切记切记
约数倍数的特征
如果一个数字x是N的约数,那么x的质约数,N中一定存在,并且N中的质约数,x中可以没有。并且x的质约数的指数一定小于等于N中相同质约数的指数
同理x是N的倍数,那么上面的结论就会反过来
求质约数
一个数字n最多有一个>n^0.5的质约数,所以我们仍然去哪只需要枚举到n^0.5
一个非常朴素的方式是枚举每个数字,判断是否是约数并判断是否是素数,复杂度接近于O(n)考虑一个数字n=(p1^a1)*(p2^a2)...*(pk^ak),其中p1<p2<p3...<pk.当我们从2枚举到n^0.5的时候,第一个满足i|n的i一定是p1,此时我们遇到了一个因子,当然也是质因子
每遇到一个质约数就将其除光,下一个约数一定是质约数。
如果最后的n!=1,那么说明剩下了一个大于n^0.5的质数(最多也只会存在一个),同时也是初始n的一个约数,也要被计入
int prime_fac[N], cnt; for(int i = 2; i * i <= n; i ++) { if(n % i == 0){ cnt ++; prime_fac[cnt] = i; } while(n % i == 0 ) n /= i;//这样n就会不断变小,这样是对的 } if(n != 1 ){ cnt ++; prime_fac[cnt] = n; }
n=(p1^a1)*(p2^a2)*..*(pk^ak),p1<p2<p3..<pk.
n的约数的个数:(a1+1)*(a2+1)*(a3+1)*..*(ak+1)。对于p1而言一共有a1+1种可能
n的约数和:(p1^0+p1^1+..+p1^a1)*...*(pk^0+pk^1+...+pk^ak).
另t=p2^a2*...*pk^ak,那么S(n)=p1^0*S(t)+p1^1*S(t)+....+p1^a1*S(t).再对S(t)进行分解就可以了
求最大公约数和最小公倍数
gcd(x,y):对于两个数字x,y,如果d既是x的约数也是y的约数,则d是x,y,的公约数,最大的d就是x,y的最大公约数
lcm(x,y):对于两个数字x,y,如果d既是x的倍数也是y的倍数,则d是x,y,的公倍数,最小的d就是x,y,的最小公倍数
特殊的,如果两个数字x,y,的最大公约数gcd(x,y)是1,则这两个数字互质。
求最大公约数
通常使用辗转相除法来实现
辗转相除法:两个数的最大公约数等于其中较小的那个数和两个数相除余数的最大公约数
gcd(a,b)=gcd(b,a%b)
复杂度O(logmax(a,b))
int gcd(int a,int b){ if(b == 0) return a; return gcd(b , a % b); }
如果给定的x,y,是以质因数乘积的表达式
x=(p1^a1)*(p2^a2)...*(pk^ak) . ai>=0
y=(p1^b1)*(p2^b2)...*(pk^bk). bi>=0
等于0是说,如果x中某个质因数pi,y中没有那么y中的bi就等于0
gcd(x,y)=(p1^min(a1,b1))*(p2^min(a2,b2))...*(pk^min(ak,bk))
lcm(x,y)=(p1^max(a1,b1))*(p2^max(a2,b2))...*(pk^max(ak,bk))
并且可以知道x*y=gcd(x,y)*lcm(x,y)
在c++的algorithm中存在一个函数 __gcd(x,y). 其中x,y,是int
写于: 2020/8/20 11:59