您的位置:首页 > 其它

NOIP提高组 2012 同余方程

2017-10-19 18:34 507 查看

题目描述

求关于 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。

/**************************
Name:同余方程
problem:求方程ax ≡ 1 (mod b)最小正整数解
By:Shine_Sky
**************************/
/***************************
ax ≡ 1 (mod b)
这是我们要求的方程
我们设有一个z使得 ax = 1 + bz
也就是 ax + bz = 1是不是很像一个东西
我说的就是拓展欧几里得
要不这样换一下 ax + b*(-z) = 1
设 y = -z
则 ax + by = 1
是不是?
我们看一下拓展欧几里得方程
ax + by = gcd(a,b)
就差后面的1了
我们假设gcd(a,b)!=1;
那么存在d是a,b的公因子且大于1
且 a = dA , b = dB;
那么ax + by = 1;
则 dA * x + dB * y = 1;
d*(Ax +By) = 1;
那么d|1所以d<=1 矛盾
所以d = gcd(a,b) = 1;
就是拓欧了
***************************/
#include <iostream>
#include <cstdio>
#define f(i,a,b)    for(register int i = a;i <= b; ++ i)
#define fd(i,a,b)   for(register int i = a;i >= b; -- i)
using namespace std;

inline int read()
{
int data  =  0 , w  =  1; char ch = 0;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') w = -1,ch = getchar();
while(ch >= '0' && ch <= '9') data = data * 10 + ch - '0',ch = getchar();
return data*w;
}

inline void write(int x)
{
if(x < 0) putchar('-') , x = -x;
if(x / 10) write(x / 10);
putchar(x % 10 + '0');
}

int a = read() , b = read() , x , y;

inline void exgcd(int a , int b , int& x , int& y)
{
if(b == 0)
{
x = 1 , y = 0;
return;
}
exgcd(b , a % b , y , x);
y -= a / b * x;
}

int main()
{
exgcd(a , b , x , y);
x += b;//最后x有可能小于0,但是我们要求的是最小正整数x
while(x > b)    x -= b;//优化%运算(个人习惯)
write(x);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: