您的位置:首页 > 其它

codevs4290 二元一次不定方程~(三星)

2015-10-25 21:36 253 查看
题目链接——————>codevsvsvsvsvsvs

题目描述 Description

背景:

(^q^/∠)

描述:

[code]已知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

[code]#1
0 0 0

#2
2 0 1


样例输出 Sample Output

[code]#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用公式:

[code]xx = (ny%b*c%b)%b;  //ny = 逆元
yy = (c-a*xx)/b;


注意点③:如果x < 0 || y < 0属于无正整数解情况~

如果上面所有的判断都不符合,那么这组解就是最优解了~,输出即可~。

下面附上完整代码:

[code]#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各位神犇
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: