扩展GCD的运用



Problem B: Xiao Ming’s Computer 
Xiao Ming is a clever boy who invented a strange computer named "Xiao Ming 
Computer". The computer has only 4 kinds of instructions: Y+=a; Y-=a; Y+=b; Y-=b; (a, 
b are two determined integers). This computer is simple, but can do many interesting 
things. Xiao Ming found that when a, b are coprime (that their greatest common 
divisor is 1), this computer is complete on addition and subtraction. 
For example, when a = 3 and b = 5, Xiao Ming would like to use this machine to 
achieve +1 operation. It can be done by the following two programs. 
Program 1: 
Y-=5; 
Y+=3; 
Y+=3; 
Program 2: 
Y+=5; 
Y-=3; 
Y-=3; 
Y-=3; 
Y+=5; 
Of course, there are many other ways to achieve. It can be proven that the first 
program is shortest. 
Xiao Ming now wants to test the performance of the machine. Can you write a 
program to turn any integer into 0 by this "Xiao Ming computer"? Furthermore, this 
program should be shortest among all correct programs. 
For example, the above two program can turn -1 to 0. And the shortest program 
executes 3 instructions. 
Input 
The first line of each case are three integers n, a, b. Here a, b (-60000≤ a, b 
≤ 60000, a≠ 0, b≠0, and gcd(a,b)=1) are the two numbers "Xiao Ming 
computer" can add or subtract. Followed by n (n<=100) lines is a 32-bit integer X 
that you should test.

Output 
For each case, the first output line "Computer" + case number +":"( starting 
with 1). Then for every X, output the least number of operations to turn it into 0.
Sample Input 
1 3 5 
2 3 7 
Sample Output 
Computer 1: 
Computer 2: 

题目大意;
本题就是求一个 n*a+m*b=c 的一组解使得| n|+|m| 尽可能的小!
资料:看到此题,开始想暴力,结果发现自己错了;其实这是一道数论题。运用到扩展GCD,求出一个特解,x0,y0;在有d=gcd(a,b),a0=a/d,b0=b/d;那么可以求出通解x=x0+a0*t;y=y0-b0*t;(a0>0,b0>0,t为整数)
不妨设a0>b0,可以证明|n|+|m|最小时有 -b
题目分析:

呼呼~~通过这个题,终于对线性同余方程有一定的了解了。呼呼~~

 

题目要我们求解方程 a * x + b * y = c ----方程[1]。

我们可以先求解方程a * x1 + b * y1 = gcd(a, b) = d。-----方程[2] 。

用扩展欧几里德就可以求出x1, y1(特解), 要使方程[2]变回方程[1], 只需要对方程[2]的两边同时除以d再乘以c就可以了。即: x0 = x1 * c / d, y0 = y1 * c / d。

 

对于有解的线性同余方程 a * x + b * y = c, 必定能够找到一组x0, y0, 使得

a * x + b * y = c = a * x0 + b * y0

进而得 a * (x - x0) = b * (y0 - y), d = gcd(a, b)=1。

又(a / d) * (x - x0) = (b / d) * (y0 - y),那么 (b/d) | (x - x0) , 设 (x - x0) = t * b / d, 代人得 y0 - y = t * a / d。 这样,可以得出通解形式

   x = x0 + b / d * t, y = y0 - a / d * t。

   此题中d=1;

 

当有多组解时,要求输出(|x| + |y|)值最小的一组。即 (| x | + | y |)= | x0 + b / d * t | + | y0 - a / d * t | = f(t), 简单分析,可以知道,   | x0 + b / d * t | 永远递增且大于零。f(t) 只有在   | y0 - a / d * t | == 0的时候 才能取得最小值。又因为 t 是整数,所以 t 应该取 (y0 * d / a) 左右的整数值。



代码如下:



#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <string>
#include <stack>
#include <cctype>
using namespace std;
int ex_gcd(int a, int b, int & x, int & y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
          return a;
    }
     int ret = ex_gcd(b, a % b, x, y);
    int t = x;
    x = y;
    y = t - a / b * y;
     return ret;
}
int main()
{

    int kk=0;
    int n,a,b,c;
    bool flag = 0;
    while (~scanf("%d%d%d",&n,&a,&b))
    {
        kk++;
        printf("Computer %d:\n",kk);
        while(n--)
        {
            scanf("%d",&c);

            flag = 0;
            if (a < b)
            {
                swap(a, b);
                flag = 1;
            }
            int x0, y0, x, y,t, f1, f2, w1, w2;
            ex_gcd(a, b, x0, y0);
            x0 *= c;
            y0 *= c;
            t = y0/a;
            if (t *a-y0>= 0)
                --t;
            f1 = abs(x0 + b*t) + abs(y0- a* t);
            f2 = abs(x0 + b*(t + 1)) + abs(y0 - a* (t + 1));
            if (f2 < f1)
                t += 1;
            else if (f2 == f1)
            {
                x = abs(x0 + b * t);
                y = abs(y0 - a* t);
                w1 = a * x + b * y;
                x = abs(x0 + b* (t + 1));
                y = abs(y0 - a* (t + 1));
                w2 = a * x + b * y;
                if (w2<w1)
                    t+=1;
            }
            int anss=abs(x0+b*t)+abs(y0-a*t);
            printf("%d\n", anss);
        }
    }

    return 0;
 
}



类似题目

poj2142  http://poj.org/problem?id=2142



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值