【模板】二元一次不定方程 (exgcd)
题目描述
给定不定方程
a x + b y = c ax+by=c ax+by=c
若该方程无整数解,输出
−
1
-1
−1。
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中
x
x
x 的最小值,所有正整数解中
y
y
y 的最小值,所有正整数解中
x
x
x 的最大值,以及所有正整数解中
y
y
y 的最大值。
若方程有整数解,但没有正整数解,你需要输出所有整数解中
x
x
x 的最小正整数值,
y
y
y 的最小正整数值。
正整数解即为
x
,
y
x, y
x,y 均为正整数的解,
0
\boldsymbol{0}
0 不是正整数。
整数解即为
x
,
y
x,y
x,y 均为整数的解。
x
x
x 的最小正整数值即所有
x
x
x 为正整数的整数解中
x
x
x 的最小值,
y
y
y 同理。
输入格式
第一行一个正整数 T T T,代表数据组数。
接下来 T T T 行,每行三个由空格隔开的正整数 a , b , c a, b, c a,b,c。
输出格式
T T T 行。
若该行对应的询问无整数解,一个数字
−
1
-1
−1。
若该行对应的询问有整数解但无正整数解,包含
2
2
2 个由空格隔开的数字,依次代表整数解中,
x
x
x 的最小正整数值,
y
y
y 的最小正整数值。
否则包含
5
5
5 个由空格隔开的数字,依次代表正整数解的数量,正整数解中,
x
x
x 的最小值,
y
y
y 的最小值,
x
x
x 的最大值,
y
y
y 的最大值。
读入输出量较大,注意使用较快的读入输出方式
样例 #1
样例输入 #1
7
2 11 100
3 18 6
192 608 17
19 2 60817
11 45 14
19 19 810
98 76 5432
样例输出 #1
4 6 2 39 8
2 1
-1
1600 1 18 3199 30399
34 3
-1
2 12 7 50 56
提示说明
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ T ≤ 2 × 10 5 1 \le T \le 2 \times {10}^5 1≤T≤2×105, 1 ≤ a , b , c ≤ 10 9 1 \le a, b, c \le {10}^9 1≤a,b,c≤109。
代码内容
// #include <iostream>
// #include <algorithm>
// #include <cstring>
// #include <stack>//栈
// #include <deque>//队列
// #include <queue>//堆/优先队列
// #include <map>//映射
// #include <unordered_map>//哈希表
// #include <vector>//容器,存数组的数,表数组的长度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//扩展欧几里得算法(裴蜀定理)
//根据费马定理,任意正整数a, b都存在整数x, y
//使得ax + by = gcd(a, b)
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;
cin>>T;
while(T--)
{
ll a,b,c;
cin>>a>>b>>c;
ll x,y;
//扩展欧几里得算法
//ax+by=gcd(a,b)=d
/*(c/d)*(a*x+b*y)=d*(c/d)*/
//a*x≡c(mod b)
//a*x=b*y+c
/*a*x+b*y=c*/
ll d=exgcd(a,b,x,y);
if(c%d)//无整数解
cout<<-1<<endl;
else
{
x*=c/d,y*=c/d;//还原
ll p,q,k;
//x 扩大,即变成 x+p
//y 缩小,即变成 y-q
p=b/d,q=a/d;
//求最小的k,使得 x+k∗p≥1 移项
//可得:k>ceil((1-x)/p)
if(x<0)//将x提高到最小正整数
{
k=ceil((1.0-x)/p);
//构造出一组船新的特解
x+=p*k,y-=q*k;
}
else if(x>=0)//将x降低到最小正整数
{
k=(x-1)/p;
//构造出一组船新的特解
x-=p*k,y+=q*k;
}
if(y>0)//有正整数解
{
//将y减到1的方案数即为解的个数
cout<<(y-1)/q+1<<" ";
//当前的x即为最小正整数x
cout<<x<<" ";
//将y取到最小正整数
cout<<(y-1)%q+1<<" ";
//将x提升到最大
cout<<x+(y-1)/q*p<<" ";
//特解即为y最大值
cout<<y<<endl;;
}
else//无正整数解
{
//当前的x即为最小正整数x
cout<<x<<" ";
//将y提高到最小正整数
cout<<y+q*(ll)ceil((1.0-y)/q)<<endl;
}
}
}
return 0;
}