gcd
1 | int gcd(int a,int b){ |
ex_gcd
前面我们用欧几里得算法gcd(a,b)=gcd(b,a%b)求得a,b的最大公约数,而扩展欧几里得算法可求得ax+by=gcd(a,b)的解,进一步可得到ax+by=m的解。
原理如下:
设a>b
- 当b=0时,很显然a*x=gcd(a,b)=a,所以x=1,而y为任意数,为了同一和方便我们令y=0;
- 当a>b>0时,设有两组等式
a*x1 + b*y1=gcd(a,b)
,b* x2+(a%b)* y2=gcd(b,a%b)
。根据欧几里得算法的递归思想,a和b的gcd为t,而a=q*b+r
,r=a-q*b
为a,b的线性组合,又因为a%t=0,b%t=0
,所以线性组合r%t=0,又有r=a%b,所以gcd(a,b)=gcd(b,a%b)
。联立等式有
a*x1+b*y1=b*x2+(a%b)*y2
,又有a%b=a-floor(a/b)* b
[这里面floor()是向下取整的意思],即:ax1+by1=bx2+[a-floor(a/b)*b]*y2
,我们将a,b视为未知数所以由x1*a+y1*b=y2*a+[x2-floor(a/b)*y2]*b可得x1=y2y1=[x2-floor(a/b)*y2]
1
2
3
4
5
6
7
8
9
10 LL exgcd(LL a,LL b,LL &x,LL &y) //扩展欧几里得算法
{
if(b==0){
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret; //返回值为gcd(a,b)
}
线性筛
寻找0到n中的质数个数,i从2到sqrt(n)依次取未被标记数j,每次从j*j到n将j(当前质数)的倍数进行标记,最后剩下全为质数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using namespace std;
int isprime(int m,int n) {
int *prime=new int[n+1];
for(int i=2; i<=n; i++)
prime[i]=1;
for(int i=2; i<=sqrt(n); i++) {
if(prime[i]==0) continue;
for(int j=i*i; j<=n; j+=i)
prime[j]=0;
}
int num=0;
for(int i=m; i<=n; i++)
num+=prime[i];
delete []prime;
return num;
}
int main() {
long long int n,m;
while(cin>>m>>n) {
cout<<isprime(m,n)<<endl;
}
return 0;
}
快速幂
1 | LL quickpow(LL x,LL n) |
斯特林公式
普通计算时:
N!=1*2*3*4*5* ............*N
;
如果要计算N!后得到的数字,则我们可以知道其等于lgN!+1lgN!=lg1+lg2+lg3+lg4+lg5+....................+lgN
;
但是当N很大的时候,我们可以通过数学公式进行优化:(即Stirling公式)N!=sqrt(2*pi*N)*(N/e)^N;(pi=3.1415926=acos(-1.0),e=2.718)lgN!=(lg(2*pi)+lgN)/2+N*(lgN-lge)
;
斯特林公式可以用来估算某数的大小结合lg可以估算某数的位数,或者可以估算某数的阶乘是另一个数的倍数。
判断一个组合数的奇偶性
C(n,k)为奇数时
n&k==k //n和k进行&位运算后还等于k
判断2的次方数
我们可以发现2的次方数n和n-1的二进制对应如下:
2 10 01
4 100 011
8 1000 0111
16 10000 01111
。。。。。。。。。。。。。。。
即n&(n-1)=0
而要确定n是2的几次方则直接数>>1右移次数即可
原码反码补码
- 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
- 反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
- 补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)
欧拉函数
欧拉函数
φ(n)表示1~n中与n互质的数的个数
容斥原理
- 在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理
- 即
A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C
欧拉定理
- 当n,a为正整数,且a和n互质时,a^φ(n)≡1(mod n);( 即[a^φ(n)]%n≡1%n )
- 应用:首先看一个基本的例子。令a = 3,n = 5,这两个数是互素的。比5小的正整数中与5互素的数有1、2、3和4,所以φ(5)=4。计算:a^φ(n) = 3^4 =81,而81 Ξ 1 (mod 5)。与定理结果相符。
这个定理可以用来简化幂的模运算。比如计算7^222的个位数,实际是求7^222被10除的余数。7和10互质,且φ(10)=4。由欧拉定理知7^4Ξ1(mod 10)。所以7^222=(7^4)^55 * (7^2) Ξ 1^55 * 7^2 Ξ 49 Ξ 9 (mod 10)
。
费马小定理
- a是不能被质数p整除的正整数,则有 a^(p-1) ≡ 1 (mod p)
- 证明这个定理非常简单,由于p是质数,所以有φ(p) = p-1,代入欧拉定理即可证明。推论:对于任意正整数a,有a^p ≡ a (mod p),因为a能被p整除时结论显然成立。
费马大定理
当整数n >2时,关于x, y, z的方程 x^n + y^n = z^n 没有正整数解。
哥德巴赫猜想
任意一个大于2的偶数,都可以写成两个质数的和
逆元
- 当求解公式:(a/b)%m 时,因b可能会过大,会出现爆精度的情况,所以需变除法为乘法:
设c是b的逆元,则有b*c≡1(mod m)
;
则(a/b)%m = (a/b)*1 %m = (a/b)*b*c %m = a*c(mod m)
;
即a/b的模等于a*c的模;- 具体求法