题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2669
题意:求线性方程a*x + b*y = c的一组整数解,其中c=1,并要求x非负。
解题方案:扩展欧几里得。若gcd(a,b)!=1,则c不是gcd(a,b)的倍数,则无解。所以如果有解,则gcd(a,b)==1,即原方程可转换为a*x + b*y = gcd(a,b)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n) memset(a,n,sizeof(a))
#define ll long long
#define N 1005
#define mod 1000000007
#define INF 0x3f3f3f3f
const double eps=1e-8;
const double pi=acos(-1.0);
ll ex_gcd(ll a,ll b,ll &x,ll &y)//a*x+b*y=gcd(a,b)
{
if(b==0)
{
x=1; y=0;
return a;
}
ll d=ex_gcd(b,a%b,x,y);
ll xx=x;
x=y;
y=xx-a/b*y;
return d;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
ll a,b;
while(cin>>a>>b)
{
ll x,y;
ll d=ex_gcd(a,b,x,y);
if(d==1)
{
while(x<0)//a(x+b)+b(y-a)=ax+by=1
{
x+=b;
y-=a;
}
printf("%lld %lld\n",x,y);
}
else
printf("sorry\n");
}
return 0;
}
将取x非负解的时候的复杂度降到O(1),参考代码: 扩展欧几里得算法详解
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define FOR(i,k,n) for(int i=k;i<n;i++)
#define FORR(i,k,n) for(int i=k;i<=n;i++)
#define scan(a) scanf("%d",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,n) memset(a,n,sizeof(a))
#define ll long long
#define N 1005
#define mod 1000000007
#define INF 0x3f3f3f3f
const double eps=1e-8;
const double pi=acos(-1.0);
ll ex_gcd(ll a,ll b,ll &x,ll &y)//a*x+b*y=gcd(a,b)
{
if(b==0)
{
x=1; y=0;
return a;
}
ll d=ex_gcd(b,a%b,x,y);
ll xx=x;
x=y;
y=xx-a/b*y;
return d;
}
ll cal(ll a,ll b,ll c)//a*x+b*y=c中x的最小正整数解
{
ll x,y;
ll gcd=ex_gcd(a,b,x,y);//得到a*x+b*y=gcd(a,b)的解
if(c%gcd!=0) return -1;
x*=c/gcd;//得到a*x+b*y=c①的解x
b/=gcd;//为得到x的最小正整数解,将方程①化为等价的a'*x+b'*y=c'②(等式两边同除以gcd),解不变 //在本题中这句可以去掉,本题只要求x非负即可
if(b<0) b=-b;//为取模方便,当b为负数时,将方程②化为等价的a''*x+b''*y=c''③(等式两边同乘以-1),解不变 //在本题中这句可以去掉,本题b>0
ll ans=x%b;//当x>0时,此时直接取到x的最小正整数解;当x<=0时,对b取模后再加b可得x的最小正整数解
if(ans<=0) ans+=b;
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
ll a,b;
while(cin>>a>>b)
{
ll ans=cal(a,b,1);
if(ans!=-1)
printf("%lld %lld\n",ans,(1-a*ans)/b);
else
printf("sorry\n");
}
return 0;
}