noip2012 同余方程 关于gcd及exgcd
来源:互联网 发布:sql declare 编辑:程序博客网 时间:2024/06/05 22:31
本文章部分参考及证明来源潘承洞《初等数论》
对于数论的话,先来一道简简单单的小题。
相信这个题大家有做过,题解也不差我一个
题面:求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。
input 两个正整数a,b。
output 一个正整数解x 数据保证该方程一定有解。
数据范围:
对于 40%的数据,2 ≤b≤ 1,000;
对于 60%的数据,2 ≤b≤ 50,000,000;
对于 100%的数据,2 ≤a, b≤ 2,000,000,000。
数据范围是10^9 必须O(n)线性过
40分简单枚举
60分我也不知道怎么能得60分QWQ
100分 exgcd 或者 欧拉定理(在这道题目有点大材小用了就不做讲解)
先讲一下exgcd
gcd 又称辗转相除法 这个用来求它的最大公约数非常显然
但是我必须给出他作为定理的证明
引理 设a,b是两个给定的整数,a不为0,那么,一定存在唯一一组整数q和r 满足 b = a * q + r 0<=r<|a|.
prove:唯一性:若不然,还有整数q‘和r’满足b = a * q’ + r‘ 0<=r’<|a|
不妨设r' >= r 二式相减得 r' - r = (q - q') * a 0<= r' - r<|a|
if (r' - r) > 0 那么有上式知道(r'-r)| |a| 所以 |a| <= r 但r' - r<|a| 矛盾
故必有r‘ = r 这就证明了它的唯一性下面证明它的存在性
当a|b时 取q = b/a r = 0
当a不整除b时 考察集合
T = {b - ka,k为整数}
显然的T中必有正整数,由最小自然数原理知T中必存在一个最小的正整数t0 = k0a > 0
只需证明t0 < |a|即可 因为a不整除b所以t0 != |a| 若t0 > |a| 那么 t1 = t0 - |a| > 0 显然可见 t1 ∈ T 故和t0 的最小性矛盾!
那么只需取q = k0 r = t0 就可以满足要求
Euclid算法 设u0,u1是两个给定的整数 u1 != 0 u1 !| u0 我们一定可以重复利用以上的引理得到下面k+1个等式
u0 = q0u1 + u2 0 < u2 < |u1| (1)
u1 = q1u2 + u3 0 < u3 < u2 (2)
u2 = q2u3 + u4 0 < u4 < u3
.............................................
u[k-1] = q[k-1]u[k] + u[k+1] 0 < u[k+1] < u[k]
u[k] = q[k]u[k+1]
prove: 对u0 u1 应用引理 由u1 !| u0知必有(1)式成立
如果u2 !| u1 就得到二式 一次这样做就有 |u1| > u2 > u3 > .........>u[j+1] > 0
由于小于u1的整数是有限的而且1整除任意整数 所以必会出现某一个k 使得u[k+1]|uk >= 1
证毕。
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
理论上while比递归好一些,不过都很基础我就懒得写了
好exgcd:
在Euclid的条件和符号下我们有以下结论
(i) u[k+1] = (u0,u1) 显然的要么我们要欧几里得算法干嘛
好吧我还是说一下吧
都知道a|b b|a b = +-a m!=0 a|b then ma|mb
由最后一式递推上去
(ii) d|u0 且d|u1的充要条件是 d|u[k+1]
利用整除的传递性和这样的一条性质就是(a|b a|c 有 对任意的x,y都有 a|bx+cy)
带入上式 即可得(ii)
(iii)存在整数x0 x1 s.t. u[k+1] = x0u0 + x1u1 这就是拓展欧几里得
prove:有第k式知道u[k+1]可以表示为u[k] u[k-1]的线性组合
由第k-1式知道 可消去u[k] 把u[k+1] 表示成u[k-1] u[k-2]的线性组合 递推上去便可以得到(iii)
大多数人背exgcd 并不是exgcd很难理解而是gcd和我们证明的引理不懂
其实也不能叫引理啦,一个数论最基础很重要的定理
#include<iostream>
#include<cstdio>
using namespace std;
int exgcd(int a,int b,int &x,int&y);
int main(){
int a,b,r,x,y;
scanf("%d %d",&a,&b);
r=exgcd(a,b,x,y);
while(x<0){
x+=b;
}
printf("%d",x);
return 0;
}
int exgcd(int a,int b,int &x,int&y){
if(b==0){
x=1;y=0;
return a;
}
int r=exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-a/b*y;
return r;
} // 代码没什么好说的很简单
- noip2012 同余方程 关于gcd及exgcd
- noip2012 同余方程 exgcd
- 洛谷 1082 [NOIP2012] 同余方程 exgcd
- NOIP2012 同余方程
- 【noip2012】同余方程
- NOIP2012 同余方程
- noip2012同余方程
- 【NOIP2012】同余方程
- [NOIP2012] 同余方程
- NOIP2012 同余方程
- [noip2012]: 同余方程
- NOIP2012同余方程
- [NOIP2012]同余方程
- [NOIP2012]同余方程
- 【Noip2012】同余方程
- NOIP2012 同余方程
- NOIP2012 同余方程 题解
- [noip2012]同余方程 题解
- LOCAL_PRIVILEGED_MODULE 详解(2)
- 你必须理解的计算机核心概念
- Excel上传并解析(java)
- 《深入理解java虚拟机》读书笔记一 【java内存区域】
- 双边滤波
- noip2012 同余方程 关于gcd及exgcd
- CUDA PTX ISA阅读笔记(一)
- 2159. Ancient Cipher
- TYVJ1463 智商问题【数据结构】【分块】
- 走近比特币:一个故事看懂“区块链”
- OpenCV学习(一、读视频)
- nginx的平滑升级,不间断服务
- TCP三次握手和四次挥手
- 解题报告:SGU