a,b,c都是整数,切ab!=0,那么形如ax+by=c的方程就是二元一次不定方程
设a,b是整数,且d=gcd(a,b),那么不定方程有无穷多个解的充要条件就是d|c。
如果不定方程有解并且特解为x=x0,y=y0,那么方程的解可以表示为
x=x0+(b/d)n
y=y0+(b/d)n
其中,n是整数
关于解不定方程ax+by=c的解法
1、计算gcd(a,b),如果gcd|c,那么方程有解,反之则无解
2、在有解的前提下,方程两边同时除以gcd,得到a1x+b1y=c1,此时一定有gcd(a1,b1)=1;
3、求出a1x+b1y=1的一组特解x0,y0,此时c1x0,c1y0是a1x+b1y=c1的一组解
4、a1x+b1y=c1的所有解为
x=c1x0+b1*t
y=c1y0+b1*t
或者对于ax+by=c,m=gcd(a,b),最小整数解为
x=(x*c%b+b)%b;
y=(y*c%a+a)%a
不定方程模板---算法导论上面的
/*模线性方程*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int gcd_extend(int a,int b,int &x,int &y)//欧几里得算法扩展形式
{
if(!b){
x=1;
y=0;
return a;}
int g=gcd_extend(b,a%b,x,y);
int t=x-(a/b)*y;
x=y;
y=t;
return g;
}
/*
void solver(int a,int b,int n)//解方程
{
int x,y;
int d=gcd_extend(a,n,x,y);
if(b%d==0)
{
int x1=x*(b/d)%n;
for(int i=0;i<d;i++)
cout<<(x1+i*(n/d))%n<<endl;
}
else
cout<<"无解"<<endl;
}
*/
void solver(int a,int b,int n)//解方程
{
int x,y;
int d=gcd_extend(a,n,x,y);
if(b%d==0)
{
int x1=x*(b/d)%n;
for(int i=0;i<d;i++)
{
int t=(x1+i*(n/d))%n;//由于负数无意义,那么负数就要判定在输出
if(t<0)
{
t=(t+n)%n;
}
cout<<t<<endl;
}
}
else
cout<<"无解"<<endl;
}
int main()
{
int a,b,n;
while(cin>>a>>b>>n)
{
solver(a,b,n);
}
return 0;
}
/*
这是模线性方程的模版,自己写的,加油
测试数据:
14 30 100
10 20 30
10 35 62
95 45
2 5 8 11 14 17 20 23 26 29
无解
*/
题目链接:http://poj.org/problem?id=1061
题意:两只青蛙跳了t步,A的坐标为x+m*t,B的坐标为y+n*t,他们相遇的条件为:x+m*t-y-n*t=p*L,即得到:(n-m)*t+L*p=(x-y)
这时求最小的t就是解一次同余方程(n-m)*t+L*p=(x-y)的最小整数解
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
long long r=ex_gcd(b,a%b,x,y);
long long t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
long long x,y,m,n,l;
long long a,b,c,g;
long long k1,k2;
while(cin>>x>>y>>m>>n>>l)
{
a=n-m;
b=l;
c=x-y;
g=ex_gcd(a,b,k1,k2);
if(c%g)cout<<"Impossible"<<endl;
else
{
a=a/g;
b=b/g;
c=c/g;
k1=k1*c;
k1=(k1%b+b)%b;
cout<<k1<<endl;
}
}
return 0;
}
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
long long gcd(long long a,long long b)
{
if(!b)return a;
else return gcd(b,a%b);
}
void ex_gcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1;
y=0;
return ;
}
ex_gcd(b,a%b,x,y);
long long t=x;
x=y;
y=t-a/b*y;
}
int main()
{
long long x,y,m,n,l;
long long k1,k2;
long long t;
long long a,b,c,g;
while(cin>>x>>y>>m>>n>>l)
{
a=n-m;
b=l;
c=x-y;
g=gcd(a,b);
if(c%g)
{
cout<<"Impossible"<<endl;
continue;
}
a=a/g;
b=b/g;
c=c/g;
ex_gcd(a,b,k1,k2);
t=c*k1/b;
k1=c*k1-b*t;
if(k1<0)
k1+=b;
cout<<k1<<endl;
}
return 0;
}
题目链接: http://poj.org/problem?id=2891
思想:这是一个接不定方程组的题目,方法与解不定方程相似
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
long long r=ex_gcd(b,a%b,x,y);
long long t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
long long a1,r1,a2,r2;
bool flag;
long long x,y;
long long n,d;
while(cin>>n)
{
flag=true;
cin>>a1>>r1;
for(long long i=1;i<n;i++)
{
cin>>a2>>r2;
long long a=a1,b=a2,c=r2-r1;
d=ex_gcd(a,b,x,y);
if(c%d!=0)
{
flag=false;
}
else
{
a=a/d,b=b/d,c=c/d;
x=((x*c)%b+b)%b;
r1+=a1*x;
a1*=(a2/d);
}
}
if(!flag)cout<<"-1"<<endl;
else cout<<r1<<endl;
}
return 520;
}
题目连接:http://poj.org/problem?id=2142
题意:输入一组a,,b,c,求出x,y使得|x|+|y|最小
思路:通过扩展欧几里得算法求出x,y,vx,vy,通过枚举的方法比较vx+vy与x+y的大小,就可以得出最小的满足题意的vx和vy
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<climits>
#include<ctime>
using namespace std;
void ex_gcd(int a,int b,int &d,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
d=a;
return ;
}
ex_gcd(b,a%b,d,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
int main()
{
int a,b,c;
int x,y;
int d;
int vx,vy;
while(cin>>a>>b>>c,a+b+c)
{
ex_gcd(a,b,d,x,y);
a=a/d;
b=b/d;
c=c/d;
vy=((y*c)%a+a)%a;//求最小的y
vx=(c-b*vy)/a;
if(vx<0)vx=-vx;
x=((x*c)%b+b)%b;//求最小的x
y=(c-a*x)/b;
if(y<0)y=-y;
if(vx+vy>x+y)
{
vx=x,vy=y;
}
cout<<vx<<" "<<vy<<endl;
}
return 520;
}
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1573
/********************************
*题意:满足同余方程组的x<m的个数
*
*思想:判断同余方程组在某个范围内的解的个数,在同余问题的基础上增加一个解不等式的过程,
*令A数组中所有数的最小公倍数是lcm,方程在lcm范围内的非负整数的解是a,则有a+lcm*x<=m,若a!=0,
*那么解的的x就是所求的个数,否则x-1就是解
********************************/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll ex_gcd(ll a,ll b,ll &x,ll&y)
{
if(!b)
{
x=1;
y=0;
return a;
}
ll r=ex_gcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return r;
}
int rr[15],aa[15];
int main()
{
ll t;
ll n,m;
ll lcm;//最小公倍数
ll a,b,c,d;
ll x,y;
bool flag;
cin>>t;
for(int k=1; k<=t; k++)
{
cin>>m>>n;
lcm=1;
flag=true;
for(int i=1; i<=n; i++)
{
cin>>aa[i];
lcm=lcm/gcd(lcm,aa[i])*aa[i];
}
for(int i=1; i<=n; i++)
cin>>rr[i];
for(int i=2; i<=n; i++)
{
a=aa[1],b=aa[i],c=rr[i]-rr[1];
d=ex_gcd(a,b,x,y);
if(c%d!=0)
{
flag=false;
break;
}
a=a/d,b=b/d,c=c/d;
x=(x*c%b+b)%b;
rr[1]+=aa[1]*x;
aa[1]*=aa[i]/d;
}
if(flag==false)
{
cout<<"0"<<endl;
//continue;
}
ll ans=0;
if(rr[1]<=m)
ans=1+(m-rr[1])/lcm;
if(ans&&!rr[1])
ans--;
cout<<ans<<endl;
}
return 520;
}