求关于 x 同余方程 ax ≡ 1 (mod b)的最小正整数解。
输入只有一行,包含两个正整数 a, b,用 一个 空格隔开。
输出只有一行包含一个正整数x0,即最小正整数解,输入数据保证一定有解。
3 10
7
【数据范围】
对于 40% 的数据, 2 ≤b≤ 1,000 ;
对于 60% 的数据, 2 ≤b≤ 50,000,000
对于 100% 的数据, 2 ≤a, b≤ 2,000,000,000
在此之前,先来了解一下欧几里德的辗转相除法的扩展:
1
2
3
4
5
6
7
8
9
10
11
12
|
int exGcd(inta,intb,
int
*x,
int
*y){
if
(b==0){
x=1;
y=0;
return a;
}
int r=exGcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return r;
}
|
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int x,y,a,b;
int kzgcd(int a1,int b1){
if(b1==0){x=1;y=0;return a1;}
else {
int ans=kzgcd(b1,a1%b1);
int t=x;
x=y;
y=t-(a1/b1)*y;
return ans;
}
}
int main()
{
cin>>a>>b;
int ans=kzgcd(a,b);
if (ans!=1) cout<<"No answer"<<endl;
else
{
x=x%b;
while (x<0) x+=b;
cout <<x<<endl;
}
return 0;
}
解法二:
假设我们知道了[0~block-1]内 i*a%b的值。
然后把接区间分成
blcok~ 2*block-1
2*block ~ 3*block -1
3*block~ 4*block -1
......................
假设解释y,那么 y 一定可以表示为 i*block+r (0<=r<=block-1)
y*a%b = (i*block +r)*a%b = 1
那么 r *a%b = (1-i*block*a%b)
我们枚举一个i ,就能得出等号右边的值 ,这是我们只需要找到最小的r,能否满足r*a%b,因为之前已经对0~block-1 内的数*a%b做过预处理,
那么不妨使用一个map做映射,这样就可以快速找r了。
- #include <iostream>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <algorithm>
- #include <map>
- using namespace std;
- typedef long long LL;
- const LL UP = 2000000000LL;
- const LL block = 100000;
- map<LL, int> mp;
- LL a,b,c;
- int main()
- {
- cin>>a>>b;
- mp.clear();
- for (LL i = 0; i < block; ++i)
- {
- LL ans = i * a % b;
- if (ans == 1) { cout << i <<endl; return 0;}
- if (mp.find(ans) == mp.end()) mp[ans] = i;
- }
- for (LL i = block; i<=UP; i+=block)
- {
- LL c = (1LL - a * i) % b;
- if (c<0) c+=b;
- if (mp.find(c) != mp.end())
- {
- cout<< i + mp[c] << endl;
- return 0;
- }
- }
- return 0;
- }