Day 2 基础数论算法
from hzwer
by Zxsure
基础概念:
假设 m 和 n 是整数,且 m 不是 0,则 m 整除 n 指的是 n 是 m 的倍
数,即存在整数 k,使得 n = mk
如果 m 整除 a - b,我们就说 a 与 b 模 m 同余并记
举个例子:
(1 ≡ 15 (mod 7))
- (15 mod 7 = 1)
- (1 mod 7 = 1)
换句话说:(a) 和 (b) 的余数相同
例题:
- 证明:如果一个数每一位加起来可以被 3 整除,那这个数就可以被 3
整除?
素数
时间复杂度
for(2~(sqrt)n)
check(i % m == 0)
素数筛法
在数列中筛去 2 ,3 ,5,7,8,9的倍数;
时间复杂度:
例题
分解质因数
假设素数是有限的,假设素数只有有限的n个,最大的一个素数是p。
[{q_{max} = (2×3×4cdots×p)+1} ]不能被所有的素数整除就找到更大的素数。
素数的唯一分解
若整数 N≥2,那么 N 一定可以唯一地表示为若干素数的乘积。
形如
- ({N = p_1^r ×p_2^r× …×p_k^r(p_i 为素数 , r_i ≥ 0)})
最小公倍数
return b = 0 ? a : gcd(b,a % b)
欧几里得算法
• ({gcd(a,b)=gcd(b, a mod b)})
• 设 g = gcd(a, b),r = a mod b,我们可以知道 a = kg + r
• 再根据 g 的最大公因数的性质(也就是同时整除a和b)就可以知道 g 也整除 r。
• 同样的,我们也可以证明,g 是同时整除 b 和 r 的最大的整数,这样,这个等式就成立了。
逆元
条件 :解决同余意义下,无法进行除法的问题
推理:
推理过程
-
我们有: inv(x)⋅x≡1 (mod p), 又据费马小定理:x^(p-1) ≡ 1 (mod p)
-
故有:inv(x)⋅x ≡ x^(p-1) (mod p) ,两边同时除以 x 有:
-
inv(x) ≡ x^(p-2) (mod p) ,这就是模质数意义下的逆元求法。
-
(inv) 表示逆元
结论
快速幂
-
求快速幂 (a^b)
-
预处理 ({a^1 a^2 a^3 cdots a^{2n} }),对b进行二进制拆分
-
如:({a^{21}=a^{16}*a^{4}*a^{1}})
练习题
CF1209A.Paint the Numbers (900)
题面:
-
给 n 个数 a1 ~ an。要求你把它们分成 k 组,使得每⼀组中的数,都能被这一组最小值整除。问 k 最小是多少?
-
n <= 100, ai <= 10000
思路 :
-
将序列排序,从头往后一次考虑最小数
-
贪心+模拟
-
以当前最小数去找到与其相关的倍数组成一组(贪)
-
贪⼼筛法,每次取没被筛掉的最小元素,筛掉它的倍数(PPT)
Code :
CF486A.Calculating Function (1100)
题面 :
-
计算函数 f(n) = -1 + 2 - 3 + .. + ( - 1)^n * n
-
n <= 10^15
思路 :
-
n 为奇数,答案是 -(n+1)/2
-
n 为偶数,答案是 n / 2
CF492B.Vanya and Lanterns (1200)
题面 :
-
一个长为 L 的街道(左端点是 0,右端点是 L)上有 n 个相同的灯,第 i 个灯放置的位置是 ai
-
问灯的半径至少要是多少,才能使得整个街道都有灯光。
-
n <= 1000, L <= 10^9
思路:
-
暴力找到灯之间的距离一半最大值
-
再比较两边界的的灯的距离。
CF570B. Simple Game (1300)
题面:
-
给 n,m,求⼀个数 a (1 ≤ a ≤ n),使得当 c 在 1 到 n 的整数中随机取值时, |c − a| < |c − m| 成立的概率最大。
-
n, m <= 10^9, m <= n
思路:
- 分 2m ≤ n 和 2m > n 讨论
CF546B.Soldier and Badges (1300)
题面 :
-
给 n 个数,每次操作可以将一个数 +1,要使这 n 个数都不相同, 求至少要加多少?
-
n <= 3000
思路:
- 排序,挨个+1
401C.Team(1400)
题面:
-
构造一个 01 序列,包含 n 个 0,m 个 1
-
要求不存在连续 2 个 0,或 3 个 1
-
无解输出 -1
-
1 ≤ n, m ≤ 10^6
思路:
-
判断无解的情况下。
-
011和01进行构造
Code
/*
2020/10/3 20:59
CF401C Team
by BZQ
*/
#include<iostream>
using namespace std;
int n,m;
int main(){
cin >> n;
cin >> m;
if(m > n*2 + 2 || n > m+1) cout << -1;//判断无解的情况
else
{
if(m > n*2){ //此处将 m >= n 的情况和 m > 2n 的情况做个合并。
for(int i = 1;i <= m - n*2; i++)//先对 m > 2n 进行预处理,之后操作一样。
cout << "1";
m = 2 * n; //注意:在做完预处理后,现在的序列就相当于是一个满011和01的序列,所以更新m;
}
if(m >= n){
for(int i = 1;i <= m - n; i++) // 先贪大后贪小
cout << "011";
for(int i = 1;i <= 2*n-m; i++)
cout << "01";
}
if(n > m){
cout << "0"; // 回复思路 1 中的问题:以为无解的边界为 n > m+1 故要想此时的 n > m 成立,当且仅当 n = m + 1;
for(int i = 1;i <= m;i++)
cout << "10";
}
}
return 0;
} //感谢观看,
413C.Jeopardy!(1400)
题面:
-
给 n 个关卡,每个关卡得分为 ai,有 m 次机会可以选择一个关卡通过后不得分,而将现有得分翻倍
-
你可以安排关卡的通过顺序和策略,求最大得分
-
1 ≤ n, m ≤ 100
思路:
- 将可以翻倍关卡放在后头,且按从一到n排序,依次贪心
POJ2689. Prime Distance
题面 :
-
给定两个整数 L, R (1 ≤ L ≤ R ≤ 2^31, R-L ≤ 10^6),
-
求闭区间[L, R] 中相邻两个素数的差最大是多少?
思路:
-
预处理({sqrt{2^{31}}});
-
暴力判断
-
使用筛法求出 [2,√R] 之间的所有素数,对于每个素数 p ,把[L,R] 中能被 p 整除的数标记,即标记 i × p(⌈L/p⌉ ≤ i ≤ ⌊R/p⌋)为合数。
-
将筛出的素数进行相邻两两比较,找出差最大的即可
235A.LCM Challenge (1600)
题面:
-
在小于n 的数中找三个数 a, b, c
-
最大化 lcm(a, b, c)
-
n <= 10^6
思路:
- 在接近 n 的数内找三个两两互质的,小范围暴力
NOIP2014. 解方程
题面:
已知多项式方程:
-
(a_0+a_1x+a_2x^2+cdots+a_nx^n=0)
-
求这个方程在 [1,m][1,m] 内的整数解(nn 和 mm 均为正整数)。
思路:
-
暴力验证[1,m]内的整数?系数太大,取模!
-
方程的解不会超过n个
-
如果(x=x_0)的时候,在对$p $ 取模后方程不成立,那么原方程必然不成立
-
用比较小的质数验证一个,先排除大部分
以上思路来源PPT,本人无思路,因为不会
作者 @Zxsure,转载请声明出处