NOIP 2012 D2 T1
原题地址:
https://www.luogu.org/problem/show?pid=1082
题目描述
求关于 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,b,可以求出形如下式的方程:
ax+by=gcd(a,b)
把参数(a,b,x,y)往扩欧算法模板里套,可以得出x,y的一组解,然后可以得出x,y的通解:
x=x0+b*k y=y0-a*k (k为整数)
扩欧函数模板:
void exgcd(ll a,ll b,ll &x,ll&y)
{
if(b==0){x=1;y=0;return;}
exgcd(b,a%b,y,x);
y=y-a/b*x;
}
证明:
y=gcd(a,b)/b-(a/b)=y0
当x增大bk的时候,y=gcd(a,b)/b-(a/b)*(x+bk)=y0-(a/b)*bk=y0-ak
然后就可以根据题目要求解决问题了。
解题思路
其实就是解方程ax-by=1,求x的最小正整数解。那么干脆转化成ax+by=1,套扩欧函数解出来x0,然后套公式求出最小正整数解就行。
参考代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define ll long long
using namespace std;
ll a,b,x,y;
void exgcd(ll a,ll b,ll &x,ll&y)
{
if(b==0){x=1;y=0;return;}
exgcd(b,a%b,y,x);
y=y-a/b*x;
}
int main()
{
cin>>a>>b;
exgcd(a,b,x,y);
while(x<0) x+=b;
cout<<x;
return 0;
}