数论初步
《算法竞赛入门经典》 10.1 数论初步学习总结
这部分内容在信息安全数学基础这门课里都有涉及,不过我没听课就是了,顺便补充代码部分。
一、欧几里得算法和唯一分解定理
Euclid Algorithm 用来求两整数的最大公因数,一言概之: 被除数与除数的最大公约数为除数与余数的最大公约数,当除数为零时,该公约数为被除数。(0是任何数的0倍) 又称辗转相除法。
int gcd ( int a , int b ) { return b==0 ? a : gcd ( b , a % b ) ; }
又因唯一分解定理,任何数可写成多个素数的乘积。
a = p1e1p2e2p3e3...prer; b = p1f1p2f2p3f3...prfr
gcd(a,b) 为 p1 到 p2 乘积, 指数为er fr 中小的; lcm(a,b) 的指数为 大的。因此两者乘积对应素数的指数固定为er+fr,即gcd(a,b) * lcm(a,b) = a * b。
二、 Eratosthenes 筛法
求1到n之间的所有素数, 筛法顾名思义, 在n个数中删除非素数即可。对于不超过n的每个非负整数p, 依次删除2p,3p, 4p, ...... 余下的即为所有素数。
// vis[i] 表示i已经被删除
memset(vis, 0, sizeof(vis)); for(int i=2, i<=n; i++) for(int j=i*2; j<=n; j+=i) vis[j] = 1;
p可限定为素数,当p取4时,要删除的数与2重复。且不能取1。 此时在二重循环前添加判断 if(!vis[i]) 即可。
且删除时不必从2p开始,因为当p为2时已经删除,应从p*p开始删除 ; --> int j = i * i 。
三、 扩展欧几里得算法
找出一对整数(x,y) , 使得 ax + by = gcd(a,b) 。
void gcd( int a, int b, int& d, int& x, int& y){ if(!b){ d = a; x = 1; y = 0;} else { gcd(b, a%b, d, y, x); y -= x * (a/b);}; }
若方程 ax + by = c 的一组整数解为 (x0, y0), 则通解为(x0+kb',y0-ka'), a' = a / gcd(a,b), b' = b / gcd(a,b), k 取任意整数。
若g = gcd(a,b) , ax + by = g 的一组解为(x0,y0), 则当c为g的整数倍时, ax+by=c的一组解为(x0c/g,y0c/g) , 当c不是g 的倍数时 该式无解。