线性丢番图方程

 

 

方程ax+by=c被称为二元线性丢番图方程

二元线性丢番图方程例题:洛谷P1516

使用拓展欧几里得算法求解x

注意:本题的拓展欧几里得算法函数需要是正数

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1;y=0;
		return a;
	}
	ll d=gcd(b,a%b,y,x);
	y-=a/b*x;
	return d;
}
ll n,m,x,y,L;
int main(){
	cin>>x>>y>>m>>n>>L;
	ll a=n-m,c=x-y;
	if(a<0){
		a=-a;
		c=-c;
	}
	ll d=gcd(a,L,x,y);
	if(c%d!=0)cout<<"Impossible";
	else cout<<((x*(c/d))%(L/d)+(L/d))%(L/d);
	return 0;
}

  

洛谷P5656

这道题使用拓展欧几里得算法求出特解后,再依次求最小解和最大解即可

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1;
		y=0;
		return a;	
	}
	ll d=exgcd(b,a%b,y,x);
	y-=(a/b*x);
	return d;
}
int main(){
	ll T,a,b,c;
	cin>>T;
	while(T--){
		ll x,y;
		cin>>a>>b>>c;
		ll d=exgcd(a,b,x,y);
		if(c%d){
			cout<<-1<<'\n';
			continue;
		}
		x=x*c/d;
		y=y*c/d;
		ll minx=(x%(b/d)+(b/d))%(b/d);
		if(!minx)minx+=(b/d);
		ll miny=(y%(a/d)+(a/d))%(a/d);
		if(!miny)miny+=(a/d);
		ll maxx=(c-b*miny)/a;
		ll maxy=(c-a*minx)/b;
		if(maxx<=0||maxy<=0){
			cout<<minx<<' '<<miny<<'\n';
			continue;
		}
		ll num=(maxx-minx)/(b/d)+1;
		ll num1=(maxy-miny)/(a/d)+1;
		cout<<num1<<' '<<minx<<' '<<miny<<' '<<maxx<<' '<<maxy<<'\n';
	}	
	return 0;
}

  

a1x1+a2x2+......+anxn=c被称为多元丢番图方程

多元丢番图方程例题:最大体积

先用裴蜀定理判定是否有解,再用完全背包计算可能的体积,最后从最大值倒序遍历求解答案

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
int n,a[N];bool flag[N];
int gcd(int a,int b){
	if(!b)return a;
	return gcd(b,a%b);
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	int Gcd=a[1];
	for(int i=2;i<=n;i++)Gcd=gcd(Gcd,a[i]);
	if(Gcd==1){
		flag[0]=1;
		for(int i=1;i<=n;i++){
			for(int j=a[i];j<=N;j++){
				if(flag[j-a[i]])flag[j]=1;
			}
		}
		for(int i=N;i>=0;i--){
			if(!flag[i]){
				cout<<i;
				break;
			}
		}
	}else cout<<0;
	return 0;
}

  

posted @ 2023-07-02 20:16  天雷小兔  阅读(74)  评论(0)    收藏  举报