简单数学和位运算

简单数学和位运算

整除和余数

  • 以下 xyax、y、a 均为整数。
  • 存在整数 kk,使得 x=kyx = ky,则有 yxy|xyy 整除 xx ),若 y>0y>0 则称 xxyy 的倍数,yyxx 的因数。
  • 如果 x=ky+ax = ky + a,则称 aax/yx/y 的余数,写作 a=xa = x % y,当 a=0a = 0 当且仅当 yxy|x

同余

  • 如果 x%z=y%zx \% z = y \% z ,则我们称 xxyyzz 同余,记作 xy(modz)x \equiv y \pmod z
  • 如果 (xy)(x − y)zz 的倍数,那么 xxyyzz 同余。
    证明:记 x=cz+a,y=dz+b0ab<z)x = cz + a,y = dz + b(0 \le a,b < z) xy=(cd)z+abx − y = (c − d)z + a − b,由于 (xy)(x − y)zz 的倍数,所以 (ab)z(a − b)|z,而 0a,b<z0 \le a,b < z,故易得 a=ba = b,所以同余。
  • 如果且 ab(modm),cd(modm)a \equiv b \pmod m,c \equiv d \pmod m ,则 a±cb±d(modz)a\pm c \equiv b\pm d \pmod z,证明雷同上面。
  • 乘号同理,但是除法不行。
  • 如果 ab(modm)a \equiv b \pmod m,则 anbn(modm)a^n \equiv b^n\pmod m

取余运算

  • (a+b)%m=(a%m+b%m)%m(a + b) \% m = (a \% m + b \% m) \% m
  • (ab)%m=(a%mb%m+m)%m(a − b) \% m = (a \% m − b \% m \color{red}+ m\color{black}) \% m
  • (a×b)%m=(a%m×b%m)(a \times b) \% m = (a \% m \times b \% m) % m
  • ab%m=(a%m)b%ma^b \% m = (a \% m)^b \% m
  • 这些等式可以用在需要取模,且数字会经过多次运算的题目中,防止中间变量超出数据范围。

质数

  • 只能被 11 和自己整除的数,称为质数
  • NN 充分大时,11 ~ NN 范围内的质数个数约为 N/logNN/\log N
  • 在某个正整数 NN 附近找质数,能够在 logN\log N 期望时间内发现一个质数。
  • 如何判断一个整数 nn 是否为质数:22n\sqrt{n} 试除,发现约数则不是质数,复杂度 O(n)O(\sqrt{n})
  • aan/an/a 中至少有 11 个数不超过 n\sqrt{n},完全平方数的情况 22 个数都等于 n\sqrt{n}

筛法(埃式筛)

  • 在学数组的时候,我们学过一个判断 11 ~ nn 是否为质数的方法:从小到大,依次将每个质数的倍数删去(若遍历到一个数时,其没有被删去,则可知这个数是质数),最终留下的全是质数。
f[1]=false;
for(int i=2;i<=n;i++) f[i]=true;
for(int i=2;i<=n;i++)
{
		if(f[i]==true)
   			for(long long j=(long long)i*i;j<=n;j+=i)
	      		f[j]=false;
}
  • jji×ii\times i 开始是因为 2×i2\times i3×i3\times i 等数字在 i=2,i=3i=2,i=3 的时候已经被枚举过了。
  • 时间复杂度 O(nloglogn)O(n\log\log n)

筛法(线性筛)

  • 数字 3030 还是被筛了多次(3×102×155×63\times 10、2\times15、5\times 6)。如果能保证每个合数都只被它的最小质因数筛掉就好了。
    比如 22 筛掉 46810124、6、8、10、12\cdots
    比如 33 筛掉 915219、15、21\cdots
    比如 55 筛掉 25355525、35、55\cdots
  • 我们记求解到 ii 的质数数组为 pp,则对于每个数字 ii,我们希望 i×p1i×p2i\times p_1、i\times p_2 等数字都被筛掉。这样一定是能筛干净的,因为合数 a=a= 某个质数 b×b\times 另一个数 cc,我们一定能在枚举到每个合数前,枚举到比它小的 cc,这样当 pj=bp_j=b 时,aa 就被干掉了。
  • 每个合数还是没有只被它的最小质因数筛。
  • 6060,被 3×203\times 20 干掉一次,被 15×415\times 4 干掉一次。
f[1]=false;
for(int i=2;i<=n;i++) f[i]=true;
for(int i=2;i<=n;i++)
{
	if(f[i]==true) p[cnt++]=i;
	for(int j=1;j<=cnt&&i*p[j]<=n;j++)
		f[p[j]*i]=false;
}
  • 内层循环加上一句if(i%p[j]==0)break;即可。为什么?
  • 此时,比 p[j] 小的质数 p[k] 不满足 p[k] i|i,且 ii 的所有质因数肯定都比 p[j] 大,因为如果有小的那 jj 早就被停在前面了。故被筛掉的 i×i\times p[k] 的最小质因数肯定是 p[k]
  • 同理可证,设有比 p[j] 大的质数 p[l] ,则删 p[l] ×i\times i 一定会出现重复,因为假设 p[l] ×i/\times i / p[j]xx,当 ii 枚举到 xx 时候,x×x\times p[j] 又会把这个数字筛一次。
  • 时间复杂度 O(n)O(n)
f[1]=false;
for(int i=2;i<=n;i++) f[i]=true;
for(int i=2;i<=n;i++)
{
	if(f[i]==true) p[cnt++]=i;
	for(int j=1;j<=cnt&&i*p[j]<=n;j++)
	{ 
		f[p[j]*i]=false;
		if(i%p[j]==0)break;
	}
}

唯一分解定理

  • 任何大于1的正整数n仅能以唯一方式分解为有限质数的乘积:
  • n=p1e1×p2e2×ptetn = p_1^{e_1} \times p_2^{e_2} \cdots \times p_t^{e_t}
  • 其中 pip_i 是质数,eie_i 是正整数,且 iiei\sum e_i都是 logn\log n 数量级别的。
  • 根据乘法定理易得 nn 的因数个数为 (e1+1)×(e2+1)××(et+1)(e_1+1)\times (e_2+1)\times\cdots\times(e_t+1)
  • 算术基本定理是一条非常基本和重要的定理,它把对自然数的研究转化为对其最基本的元素——质数的研究。

质因数分解

  • 22n\sqrt{n} 都试一下,如果能除的尽 nn 就用 while 除,要把次数记下来。
  • 最后剩下的数字如果步数 11 ,一定是最大的质因数。

gcd 和 lcm

  • mxm|xmym|y ,称为 mmxxyy 的公因数。最大的 mm 叫最大公因数 (gcd)(gcd)
  • xnx|nyny|n,称为 nnxxyy 的公倍数。最小的 nn 叫最小公倍数 (lcm)(lcm)
  • d=gcd(x,y)d = \gcd(x,y),那么 dd 的唯一分解中任意质数的指数 eie_ix,yx,y 的唯一分解中此质数指数的 min\min
  • e=lcm(x,y)e = lcm(x,y),那么 ee 的唯一分解中任意质数的指数 eie_ix,yx,y 的唯一分解中此质数指数的 max\max
  • 比如 gcd(240,180)=60\gcd(240,180)=60,分解质因数如下,发现 6060 的质因数中 2233的指数取得是上面两个数分解 2233 的指数的最小值
    • 180=22×32×51180 = 2^2 \times 3^2 \times 5^1
    • 240=24×31×51240 = 2^4 \times 3^1 \times 5^1
    • 60=22×31×5160 = 2^2 \times 3^1 \times 5^1
  • lcmlcm 则是取最大值,易得 gcd(x,y)×lcm(x,y)=x×y\gcd(x,y) \times lcm(x,y) = x \times y

位运算

  • &\& 运算:二进制下进行二元运算,每一位全 1111 ,反之为 00。性质:a&bmin(a,b)a\&b\le \min(a,b).
  • | 运算:二进制下进行二元运算,每一位有 11 则1,反之为 00。性质:abmax(a,b)a|b\ge \max(a,b).
  • ^ 运算:二进制下进行二元运算,每一位不同则 11,反之为 00。性质是自己就是自己的逆运算。
  •  ~ 运算:一元运算符(和符号一样),让二进制下的每一位都取反(包括符号位)。
  • <<<<运算:进制下把每一位向左平移,低位用 00 补足。
  • 1<<n1<<n 等价于 2n2nx<<nx<<n 等价于 x×2nx \times 2n
  • >>>>运算:进制下把每一位向右平移,低位越界则舍弃。
  • n>>1=n2n>>1=\lfloor\frac{n}{2}\rfloor
  • 注意位运算优先级很低\color{red}优先级很低,搞不清就打括号!

一些其他操作

  • lowbit(n)lowbit(n) 表示表示二进制下 nn 的最低的一个 11 它后面的 00 组成的数.
  • lowbit(n)=n&nlowbit(n)=n\&-n,原理自己想。
  • popcount(n)popcount(n) 表示二进制 nn 有多少位是 11,原理自己想。
int ans=0;
while(n)
{
	ans++;
	n-=lowbit(n);
}
return ans;

一些其他的其他操作

  • 检测第 kk 位是 0/10/1(n&(1<<(k-1)))!=01\to1
  • 给第 kk 位取反:n^=(1<<(k-1))
  • 给第 kk 为赋值为 11n|=(1<<(k-1))
  • 给第 kk 为赋值为 00n&=(~1<<(k-1))
posted @ 2023-07-22 14:54  sLMxf  阅读(12)  评论(0)    收藏  举报  来源