题目链接——————>codevsvsvsvsvsvs
题目描述 Description
背景:
(^q^/∠)
描述:
已知a,b,c, 求满足ax+by=c的整数对(x,y)中x为正整数且最小;
若此时0<=x,y,则输出x y,若此时y<0则输出“sometimes naive”(没有双引号);
若没有整数对(x,y)满足条件则输出“too simple”
输入描述 Input Description
输入
一行 三个数,a,b,c;
输出描述 Output Description
输出
一行,x y或too simple或sometimes naive
样例输入 Sample Input
#1
0 0 0
#2
2 0 1
样例输出 Sample Output
#1
0 0
#2
too simple
数据范围及提示 Data Size & Hint
数据范围
30% 0<=a,b,c<=10;
70% 0<=a,b,c<=500000000;
100% 总之我这个渣渣能过;
题解:
这题我经历了几个阶段:认真做->弃疗->认真做->找大神->大神讲(space-time Orz)->AC;
别的不说,直接开解~
这题显然exgcd,但是暴力for也能拿60分左右。
我们先来讨论那几个特殊情况,即无解和无正整数解的情况。
1、 a == b == 0的情况,样例1,输出“0 0”
2、a == 0 && b != 0的情况
这时原方程变成了一元一次方程,无整数解得情况就是c%b != 0的情况,因为不能整除,这时输出“too simple”,如果满足整除,再看c/a是否是正整数输出。
3、a != 0 && b == 0 同上处理~
4、a != 0 && b != 0的情况下:
开始我想直接暴力取出exgcd的答案,然后利用while循环来得到最小值,但是这样我爆了,于是弃疗了一段时间。
之后一个叫space-time的大神给我讲了一下,我才了解了方程可以这么解……
下面将具体解答:
ax + by = c;
by = (c - ax);
y = (c-ax)/b;
因为y是整数,所以(c-ax)必定整除于b,即b|(c-ax);
然后根据取模的性质:(c%b-ax%b)%b = 0;
得到同余方程:ax=c(mod b);
将x移过去得:x = c/a(mod b);
对于y,只要求得x就能求得y了,所以现在的主要目的是求得x,根据同余方程,只要求得c/a就能求得x了,这里在取模意义下的除法,可以对a求在mod b意义下的逆元,然后转化成乘法求得x即可~
这里还是有许多细节问题:
①首先对a,b,c求最大公约数,进行约分,减小爆掉的可能
②如果不存在逆元显然属于无解的情况~
嗯 处理出来逆元之后对x用公式:
xx = (ny%b*c%b)%b; //ny = 逆元
yy = (c-a*xx)/b;
注意点③:如果x < 0 || y < 0属于无正整数解情况~
如果上面所有的判断都不符合,那么这组解就是最优解了~,输出即可~。
下面附上完整代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll a,b,c,xx,yy;
ll gcd(ll a,ll b) {return b == 0 ? a : gcd(b,a%b);};
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(a == 0 && b == 0) return -1;
if(b == 0) {x = 1,y = 0; return a;}
ll d = exgcd(b,a%b,x,y);
ll t = x;
x = y,y = t-a/b*y;
return d;
}
int main()
{
scanf("%lld%lld%lld",&a,&b,&c);
if(a == 0 && b == 0){puts("0 0"); return 0;}
if(a == 0)
{
if(c % b) {puts("too simple"); return 0;}
ll k = c / b;
if(k >= 0) {printf("0 %lld\n",k); return 0;}
else {puts("sometimes naive"); return 0;}
}
if(b == 0)
{
if(c % a) {puts("too simple"); return 0;}
ll k = c / a;
if(k >= 0) {printf("%lld 0\n",k); return 0;}
else {puts("sometimes naive"); return 0;}
}
ll gg = gcd(a,(gcd(b,c)));
if(gg > 0) {a /= gg,b /= gg,c /= gg;}
ll x,y,d = exgcd(a,b,x,y);
if(d != 1) {puts("too simple"); return 0;}
ll ny = (x%b+b)%b;
xx = (ny%b*c%b)%b; yy = (c-a*xx)/b;
if(xx < 0 || yy < 0) puts("sometimes naive");
else printf("%lld %lld",xx,yy);
return 0;
}
// 4 7 8
2333 蒟蒻Orz各位神犇