专栏文章
题解:P5656 【模板】二元一次不定方程 (exgcd)
P5656题解参与者 4已保存评论 8
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 8 条
- 当前快照
- 1 份
- 快照标识符
- @mio6ul86
- 此快照首次捕获于
- 2025/12/02 14:19 3 个月前
- 此快照最后确认于
- 2025/12/02 14:19 3 个月前
解析
恭喜你已经会了第一步,成功的掌握了前置知识,现在我们继续研究,先从求解 gcd 入手吧!
相信聪明的你一定会辗转相除求 gcd 吧,我们来模拟一下这个过程,假设现在有 和 两个数:
第一轮: 较小数不为零,继续 gcd
第二轮: 继续 gcd
第三轮: 继续 gcd
第四轮: 继续gcd
第五轮: 较小数为零了,返回。
我们回头再看每一轮的操作,假设现在的第一个数为 ,第二个数为 ,现在即将生成下一轮的两个数 。
不用多说, 怎么办呢?
好吧,其实 。
因此,我们可以不断用 去代换 ,用 取代换 ,最后 gcd 就可以用 来表示了,方程得解。
大功告成,现在我们已经成功得到了一组解 和 ,回到 中,则 ,,然后将等式两边同时除以 gcd。
得到
现在假设存在另外一组 和 使等式成立,则我们可以这样表示 和 :
考虑 ,则 ,可得 ,那么 , 同理可得。
再考虑 ,因为 和 肯定是你增我减才能使等式依然成立,则 时取到 , 时取到 。
那么解的个数是多少呢? 因为 最大值与最小值之间每 个数就有一个解,所以个数为 个。
最后一步,判定是否无正整数解,不难发现,若 取最小值时, 那么 肯定无法更大了,因此可以判定为无解。
最后代码奉上:
CPP#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
int aa, bb, cc, ans = 0, jx = 0, jy = 0;
int x, y = 0;
void exgcd(int a, int b, int xa, int ya, int xb, int yb){//求一组特殊解
if(b == 0){
ans = a;
jx = -xa;
jy = -ya;
return ;
}
else{
int k = a / b;
exgcd(b, a % b, xb, yb, xa - k * xb, ya - k * yb);
}
}
signed main()
{
int T = 0;
cin >> T;
for(int t = 1; t <= T; t++){
cin >> aa >> bb >> cc;
exgcd(aa, bb, -1, 0, 0, -1);
if(cc % ans != 0){//判定无解
cout << -1 << endl;
continue;
}
aa = aa / ans;//化为最简式
bb = bb / ans;
cc = cc / ans;
jx = jx * cc;
jy = jy * cc;
double ka = ceil((1.0 - jx) / bb);
int xmin = jx + bb * ka;
double kb = floor((jy - 1.0) / aa);
int ymin = jy - aa * kb;
int xmax = (cc - bb * ymin) / aa;
int ymax = (cc - aa * xmin) / bb;
if(xmax <= 0){//判定无正整数解
cout << xmin << ' ' << ymin << endl;
continue;
}
else{
cout << (ymax - 1) / aa + 1 << ' ' << xmin << ' ' << ymin << ' ' << xmax << ' ' << ymax << endl;
}
}
return 0;
}
本人第一次写题解,管理大大求过 QwQ。
具体哪里有错说一下吧QwQ
相关推荐
评论
共 8 条评论,欢迎与作者交流。
正在加载评论...