整除
a对b向下取整:a // b
a对b向上取整:(a+b-1) // b
整除:a整除b,记为a|b,说明b%a == 0,即b是a的倍数,a是b的因数
性质:
如果a|b、blc,则alc
如果cla、c|b,则c|(ma+nb)
同余
设整数 m ≠ 0 ,且m | (a-b),则 a 同余于 b 模 m ,换句话说: a 和 b 在模 m 意义下同余
记为 : a ≡ b(mod m)
同余的性质:
自反性:a≡a(mod m)
对称性:若a≡b(mod m),则b≡a(mod m)
传递性:若a≡b(mod m),b≡c(mod m),则a≡c(mod m)
线性运算:若a≡b(mod m),c≡d(mod m),则: a±c≡b±d(mod m),axc≡bxd(mod m)
一般在求解问题时题目要求最终答案对mod求余,只需要每次运算均保持求余即可,
因为:
(a+b)%mod=((a%mod)+(b%mod))%mod
(axb)%mod=((a%mod)x(b%mod))%mod
上述性质保证只要运算中不出现除法,最终答案对mod求余,可以转换成每次运算均求余,答案不会发生变化。
GCD和LCM
GCD
假设a>b,a=bk+c,其中k是a/b的商,c是a/b的余数,其中c=a%b<b
则有:gcd(a,b)=gcd(b,c),即gcd(a,b)=gcd(b,a%b)
假设p= gcd(a,b),q=gcd(b,c),有pla,plb,q|b,q|c
由于c=a-bk⇒plc⇒ p是b,c的公因子 ⇒ q≥ p
由于a=bk+c⇒qla⇒q是a,b的公因子 ⇒ p≥q
最终:p=q
求最大公因数:
方法一(递归法):
python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
x, y = map(int, input().split())
print(gcd(x, y))
方法二(使用库函数):
from math import *
里面也有gcd函数,和上述功能相同,但是可以传递多个数字,计算多个数字的gcd
python
from math import gcd
print(gcd(4, 6, 10))
LCM
gcd(a,b) * lcm(a,b) = ab
lcm(a,b) =ab / gcd(a,b)
python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def lcm(a, b):
return a * b / gcd(a, b)
例题


代码如下:(有一组数据运行超时)
python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def lcm(a, b):
return a * b / gcd(a, b)
n = int(input())
for _ in range(n):
a0, a1, b0, b1 = map(int, input().split())
ans = 0
for x in range(1, int(b1 ** 0.5) + 1):
if b1 % x != 0:
continue
if x % a1 == 0:
if gcd(x, a0) == a1 and lcm(x, b0) == b1:
ans += 1
y = b1 // x
if y != x:
if y % a1 == 0:
if gcd(y, a0) == a1 and lcm(y, b0) == b1:
ans += 1
print(ans)
埃氏筛

代码如下:
python
def get_prem(n):
#prem存储所有素数
prem = []
#a表示是否已标记
a = [0] * (n + 1)
##从2-n遍历所有数字,找到第一个未标记的数字,即为素数
for i in range(2, n + 1):
if a[i] == 0:
prem.append(i)
#将所有倍数全部标记
for j in range(i + i, n + 1, i):
a[j] = 1
return prem
n = int(input())
prem = get_prem(n - 1)
print(*prem)
print(len(prem))
线性筛
埃式筛法缺点:一个合数被筛好几次 -- 能否一个合数只被筛1次呢?
线性筛:一个合数只被最小质因子筛一遍
python
def get_prime(n):
vis = [0] * (n + 1) # vis[i]=1 表示合数
prime = [] # 存储素数
for i in range(2, n + 1):
if vis[i] == 0: # i是素数
prime.append(i)
# 用当前素数去筛掉 i * prime[j]
for now_prime in prime:
if i * now_prime > n:
break
vis[i * now_prime] = 1 # 标记为合数
# 关键:保证每个合数只被它的最小质因子筛掉
if i % now_prime == 0: # now_prime 是 i 的最小质因子
break
快速幂
如何快速求解a^b%c
传统方法,循环b次,时间复杂度O(b)
快速幂:在log时间内求解

如何快速求解a^b%c
如果b为偶数,则计算a^(b/2),在此基础上计算平方
如果b为奇数,则计算a^(b/2),在此基础上计算平方再乘上a
求余操作在每次运算时均做一次求余答案不变
例题

代码如下:
python
def ksm(b, p, k):
if p == 0:
return 1
if p == 1:
return b % k
ans = ksm(b, p // 2, k)
ans = ans * ans % k
if p % 2 == 1:
ans = ans * b % k
return ans
b, p, k = map(int, input().split())
print(ksm(b, p, k))
唯一分解定理
唯一分解定理:也叫做算数基本定理,任意一个大于1的整数N,要么为质数,要么可以分解为有限个质数的乘积。

其中p1<p2 <...< pk,并且均为质数,q1,...,qk为正整数。
上述分解形式是一定存在且唯一的(可以看做质因子分解)
从小到大枚举所有质数x,然后如果x能整除,则不断除以x,直至除尽
需要预处理所有质数?
不需要,直接从小到大枚举可以整除的数字即可。
因为只要能整除,一定是质数,因为按照上述策略不可能存在整除合数的情况,合数一定会进一步分解为质数。
例题

代码如下:
python
def solve(n):
factor = []
for i in range(2, n + 1):
while n % i == 0:
n //= i
factor.append(i)
if n == 1:
break
return factor
a, b = map(int, input().split())
for i in range(a, b + 1):
factor = solve(i)
print("{}=".format(i), end ='')
print(*factor, sep = '*')
因子数、因子和

例如:15=3^1*5^1,因子为1,3,5,15,因子数为(1+1)(1+1)=4,因子和为(1+3)(1+5)=24。满足上述性质。
例如:36=2^2*3^2,因子为1,2,3,4,6,9,12,18,36,因子数为(2+1)(2+1)=9,因子和为(1+2+4)(1+3+9)=91。满足上述性质。
例题

python
from collections import Counter
def solve(n):
factor = []
for i in range(2, n + 1):
while n % i == 0:
n //= i
factor.append(i)
if n == 1:
break
return factor
all_factor = []
for i in range(2, 101):
all_factor += solve(i)
all_factor = Counter(all_factor)
ans = 1
for k, v in all_factor.items():
ans *= v + 1
print(ans)