qbxt Day3 on 2019-8-18
qbxt Day3 on 2019-8-18
一、基础数论
1.进制转换
进制转换是一个非常简单且基础的问题。
也许我们只需要...Emmm...
列个式子就好了鸭
设\(k\)进制数每一位上是\(a_i\),那么\((x)_k=\sum\limits_{i=1}^{\texttt{位数}}a_i*k^{i-1}\)
这是任意进制下数字的转换
和进制的转换有关的题目大多数围绕这个式子有关。
(NOIp普及组那个可以直接表示一位就够了)
2.辗转相除法(欧几里得算法)
辗转相除法应该是最简单的数论(数论只会gcd)
然后实现方式也很简单,是log级别的。
inline int gcd(int a, int b)
{
int temp;
while (b) temp=a,a=b,b=temp%b;
return a;
}
为什么呢?我们假设\(a\geq b\),那么\(a{\%}b\leq \frac{a}{2}\)。
因此我们这样做的复杂度上限应当最大就是\(O(logn)\)的。
证明的话
由裴蜀定理可以推得,\(gcd(a,b)=gcd(b,a\%b)\),所以我们一直向下直到......\(b=0\)即可。
然后\(lcm(a,b)\)的话其实就是\(\frac{a\times b}{gcd(a,b)}\)
3.扩展欧几里得(exgcd)
这个算法是算一个等式的一组特解
然而这个算法其实也是一个log的
怎么做呢
就是根据\(gcd(a,b)=a(b=0)\),然后我们一直先递归求\(gcd(a,b)\),然后直到某一层\(k\)会有一个
显然这个时候\(x_k=1,y_k=0\)
那么我们怎么根据这个式子往回回溯求一开始的\(x_0,y_0\)呢?
我们可以举一个例子(举第一层的例子吧)
设\(a\cdot x_0+b\cdot y_0=gcd(a,b)\)
那么下一层就是\(b\cdot x_1+(a\bmod b)\cdot y_1=gcd(a,b)\)
我们可以知道\((a\bmod b)=a-b\cdot\big\lfloor{\frac{a}{b}}\big\rfloor\),而且\(a\cdot x_0+b\cdot y_0=b\cdot x_1+(a\bmod b)\cdot y_1\)
替换式子之后会得到\(a\cdot x_0+b\cdot y_0=b\cdot x_1+(a-b\cdot\big\lfloor{\frac{a}{b}}\big\rfloor)\cdot y_1\)
拆开,得到\(left=a\cdot y_1+b(x_1-\big\lfloor{\frac{a}{b}}\big\rfloor\cdot y_1)\)
于是乎因为\(a,b\)都是一样的
那么\(x_0=y1,y_0=x_1-\big\lfloor{\frac{a}{b}}\big\rfloor\cdot y_1\)
回溯就可以了
代码实现:
//返回的是gcd(a,b)
int exgcd(int a,int b,int &x,int &y)
{
if (b==0) //可以直接回溯了
{
x = 1, y = 0;
return;
}
int d = exgcd(b, a % b, x, y);
int temp = x; //
x = y; //
y = temp - (a / b) * y; //从下一层向这一层回溯
return d;
}
有三个重要的式子,这里就不再赘述 反正我也不会证明
4.数论分块
烧脑预警
首先我们了解\(\big\lfloor{\frac{x}{i}}\big\rfloor,i\in [1,x]\)的话是只有\(\sqrt{x}\)种取值的。
至于证明的话,我们可以分\([1,\sqrt{x}]\)和\([\sqrt{x}+1,x]\)两部分
因为我们知道前半部分是有\(\sqrt{x}\)种取值的,那么由于因子是对称的,因此另外一部分也是有\(\sqrt{x}\)种取值的。
因此我们直接开始Emmm...枚举根号次就好了
代码模板
void fenkuai(int n)
{
for (int i = 1, last; i <= n; i = last + 1)
{
int a = n / i;
last = n / a; // n / (n / i) 是与 n / i相同值的最大i......
/* your code */
}
}
然后呢,这样可以优化某一些枚举\(\big\lfloor{\frac{x}{i}}\big\rfloor\)的值的数论题目......
几个例题
1.求:
数据范围:
一看只好跑一个数论分块
首先我们知道上面的结论之后可以直接优化
就是说\((\big\lfloor\frac{n}{i}\big\rfloor)^3\)的取值只有\(\sqrt{n}\)种,因此我们合并有这一项的式子,可以得到
这样就直接求了qwq
(LaTeX打得我心痛)
算了剩下的例题实在是不想敲了QAQ
二、质数筛法和欧拉函数
1.埃拉托色尼筛法
这个应该是最熟悉的了吧......
每次拿到一个质数,摁着质数向下筛他的倍数。
由于质数是log的,质数的倍数是log(log)级别的,因此整个算法的复杂度就是\(O(nlog(logn))\)的。
这个算法的最大缺点在于一个数有可能会被筛很多遍
这是没有必要的鸭
因此我们设计了一个方式防止重复筛一个数
只让一个数的最小的因子筛掉他
2.欧拉筛
没错就是它。
我们每次筛掉一个数一定是被最小的因子筛掉(除去1是预处理的)
于是我们就可以直接枚举质数p,当i可以被某一个质数筛掉,就停下筛下一个数。
为什么这样做是对的???
因为避免了大的质数筛掉较小的数字,保证了每一个数只会被筛一次。
当然同时我们还可以预处理每一个数的最小的因子,得到这个数组之后我们可以log时间内枚举一个数的所有质因子。
3.欧拉筛配备积性函数
这有什么好说的......
首先积性函数就是指在自然数范围内\(f(a)\cdot f(b)=f(a\cdot b)\)的函数。
然后的话有欧拉函数和莫比乌斯函数作为积性函数的代表,登上历史舞台。
代码先鸽这着...
4.组合数
组合数当然是开心至极
那句小葱同学******是什么来着???
定义\(C^n_k\)表示在n个元素中取出k个元素的方案数
通常情况下我们计算组合数都要搭配容斥原理来做各种毒瘤。
然后这个容斥原理还要搭配莫比乌斯函数来进行毒瘤。
来个例题
给定n个数的序列\(a_1..a_n\),求将序列分成两组使得两组的or和相等(数据保证有解)的方案数。
数据范围:
那岂不是直接就做了(大雾)
我们按照每一个二进制位考虑
假设现在我们在检查第i个位,有以下几种情况:
- 数据中所有的数这一位都是0或者1
那么这样就直接不用计数了,怎样分都是一样的......答案乘\(C^n_{\frac{n}{2}}\) - 如果不是都是1,那么必须有一组里面的数这一位有1,但是这并不好统计不是吗
但是我们可以考虑统计补集
然后套一个并查集就OK了
代码还是不写
5.组合八题
什么毒瘤
- 小球不等价,盒子不等价,盒子可以为空,有多少种方案?
- 小球不等价,盒子不等价,盒子不能为空,有多少种方案?
- 小球不等价,盒子等价,盒子不能为空,有多少种方案?
- 小球不等价,盒子等价,盒子可以为空,有多少种方案?
- 小球等价,盒子不等价,盒子可以为空,有多少种方案?
- 小球等价,盒子不等价,盒子不能为空,有多少种方案?
- 小球等价,盒子等价,盒子不能为空,有多少种方案?
- 小球等价,盒子等价,盒子可以为空,有多少种方案?
具体是什么上网上去查吧......