题目描述
求关于 x
的同余方程 ax≡1(mod b)
的最小正整数解。
输入格式
一行,包含两个正整数 a,b
,用一个空格隔开。
输出格式
一个正整数 x0
,即最小正整数解。输入数据保证一定有解。
输入输出样例
输入 #1
3 10
输出 #1
7
说明/提示
【数据范围】
对于 40%的数据,2≤b≤1,000;
对于 60%的数据,2≤b≤50,000,000;
对于 100%的数据,2≤a,b≤2,000,000,000。
NOIP 2012 提高组 第二天 第一题
思路
题意:满足 a*x mod b = 1
的最小正整数 x
。(a,b
是正整数)
a*x mod b = 1
<=> (a*x) mod b = 1
<=> (a*x) - k*b = 1
,k为常数(整数)
(a*x) - k*b = 1
<=> a*x + b*y = 1
,y=-k
所以a*x mod b = 1
等价于a*x + b*y = 1
由裴蜀定理,对于整数a,b
和正整数x,y
,ax + by = c
成立的充要条件是gcd(a,b) % c = 0
.
在本题中,gcd(a,b)% 1 = 0
,所以gcd(a,b) = 1
因而问题转化为求a*x + b*y = gcd(a,b)
的最小正整数解,可以应用拓展欧几里得算法(exgcd),然后将x
处理为最小正整数即可
拓展欧几里得
代码
void exgcd(int &x,int &y,int a,int b){
//使用时exgcd(a,b,a,b)即可,无需全局变量,运行后a、b为一组解
if(!b){
x=1,y=0;
return;
}
exgcd(x,y,b,a%b);
int t;
t=x,x=y,y=t-a/b*y;
}
压行版本
void exgcd(int &x,int &y,int a,int b) {
if(!b) x=1,y=0;
else exgcd(y,x,b,a%b),y-=a/b*x;
}
AC
代码
//#pragma GCC optimize(2)
//std::ios::sync_with_stdio(0)
//clock_t st=clock();
#include<bits/stdc++.h>
#define abss(x) ((x)>(0)?(x):(-1)*(x))
#define maxs(a,b) ((a)>(b)?(a):(b))
#define mins(a,b) ((a)<(b)?(a):(b))
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(int i=(a);i>=(b);--i)
#define mem(a) memset(a,0,sizeof(a))
const int INF (1<<30);
const int inf (-1<<30);
using namespace std;
void exgcd(int &x,int &y,int a,int b){
if(!b){
x=1,y=0;
return;
}
exgcd(x,y,b,a%b);
int t;
t=x,x=y,y=t-a/b*y;
}
int main(){
int a,b,x,y;
cin>>a>>b;
x=a,y=b;
exgcd(x,y,a,b);
x=(x%b+b)%b;//负数回正,大的变小,得到最小正整数解
cout<<x;
return 0;
}