素数判定
一般从2判到sqrt(n)就够用了
还有一个miller-rabin
题目 NOIP2012 质因数分解
素数筛法
O(n log n)
筛到素数后标记其倍数,因为会重复所以是O(n log n)
线性筛
for(int i=2;i<=n;++i)
{
if(!vis[i])pr[++num]=i;
for(int j=1;j<=num&&pr[j]*i<=n;++j)//后一个判定条件是为了防止超出去
{
vis[pr[j]*i]=1;
if(!(i%pr[j]))//这里的判定使得算法复杂度为O(n)而非O(n log n)
break;
}
}
这里就只解释一下最关键的语句是怎么起作用的吧。
他保证了一个合数只会被它最小的质因子筛到,比如(2^5)(3^3)(5^7)
它只会被2在乘以(2^4)(3^3)(5^7)时筛掉
很灵性的一个东西。。。真的挺难想出来的。。。
这个东西还是好好背代码吧
gcd-欧几里得
int gcd(int x,int y)
{
return x%y?gcd(y,x%y):x;
}
只给出它是O(log n)的证明
我们可以证明:a%b<a/2
分以下两种情况:
①b<=a/2
那么显然a%b<a/2
②b>a/2
那么a%b=a-b,显然小于a/2
所以他的复杂度是O(log n)
扩展欧几里得
这个算法是用来解ax+by=gcd(a,b)这样的方程(当且仅当右边为gcd(a,b)时,x,y有整数解)
由于gcd(a,b)=gcd(b,a%b) [欧几里得算法的结论]
那我们可以弄下去
假设存在x
,y
使得bx
+(a%b)y
=gcd(b,a%b)=gcd(a,b)
由于a%b=a-floor(a/b)
将其代入,拆式子,合并同类项,得
ay
+b(x
-floor(a/b)*y
)=gcd(a,b)
即x=y
,y=x
-floor(a/b)*y
,这为我们后面从底部反推回来做好了铺垫
递归到底,一定会有
gcd(a,b)x
+0*y
=gcd(a,b)
此时显然x
=1,y
=0是它的一组解
然后我们按照上面推的式子推回去,就得到了这个不定方程的一组解
这个代码return 的是gcd(a,b)。。。
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int ans=exgcd(b,a%b,x,y);
int temp=x;
x=y;//划重点
y=temp-a/b*y;//划重点
return ans;
}
例题:同余方程
LCM
lcm(a,b)=a*b/gcd(a,b)
建议先除以,防止溢出
快速幂
这也算数论内容???难道不是倍增???
建议:用while()而不要用递归,不然常数会比较大
逆元
逆元的定义:若x*y
1(mod p),那么y为x的逆元
只有x与p互质时,x才存在逆元
逆元满足交换、结合、分配律
求逆元的方法:
①exgcd
ax
1(mod p)
ax-p*floor(a/p)=1
ax+py=1
用exgcd解这个不定方程即可
②费马小定理
条件:p是质数且a,p互质
结论:若p是质数,且a,p互质,那么a
1(mod p)
显然,a*a
1(mod p)
用快速幂求解即可
引入.欧拉函数
定义ψ(n)为[1,n]中与n互质的数的个数(1也算)
如ψ(4)=2,ψ(6)=2
记k的质因数分解形式为k=p
*p
…p
那么ψ(k)=k*(1-1/p
)(1-1/p
)…(1-1/p
)
这个式子可以用容斥原理证明,其实是先找出k中含有质因数pi的个数之类的…
而且ψ(n)是个积性函数
神奇的是这个函数还可以用欧拉筛来求
讨论两种情况
①ψ(2
3
5
)=ψ(2
3
5
)*2 //因为后面的那些分数已经没差了,差的只是前面的k,所以才能这样求,把求的式子写开就能看出来
②ψ(2
3
5
)=ψ(3
5
)*ψ(2
) //因为这时差的不只有k,还有分数那里也差一个,这也说明了ψ(n)是一个不完全积性函数
③欧拉公式
介绍完了欧拉函数ψ(n),我们就可以来用欧拉公式了
其实费马小定理也只是欧拉公式的一个特殊情况!
条件:a,p互质,即gcd(a,p)=1 (也就是逆元存在的条件)
公式如下:
a
%p=1
可以看出来,费马小定理的条件下ψ(p)=p-1,所以可以那样来弄
由欧拉公式就得出了%p意义下a的逆元为a
组合数
同余方程组
中国剩余定理
ex-gcd解同余方程组
题目:Hankson的趣味题