Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6001 | Accepted: 2612 |
Description
Input
Output
Sample Input
700 300 200 500 200 300 500 200 500 275 110 330 275 110 385 648 375 4002 3 1 10000 0 0 0
Sample Output
1 3 1 1 1 0 0 3 1 1 49 74 3333 1
Source
题意:有两种类型的砝码,每种的砝码质量a和b给你,现在要求称出质量为d的物品,要求a的数量x和b的数量y最小,以及x+y的值最小。
解题思路:是扩展欧几里得的应用。设ax + by = gcd(a,b),求出x和y的值,因为我们要求ax + by = n的解,所以需要将x y的值乘以n/gcd(a,b)。因为题目中要求x和y的值都要为正,然而,易知,ax + by = gcd(a,b)在a和b都为正数的情况下,x 和 y必有一个数是负的。因此我们需要把x 和 y的值转化为合法的正值。我们先把x转化为正值,易知,把x转化为正值的方式是 x = (x % (b/gcd(a,b))+(b/gcd(a,b)) %(b/gcd(a,b)),这样x就成为最小的正值,我们再根据所求出的x的最小正值求出y的值,则 y = (n – a * x) / b,若求出的y为负值,则把y变正,意思就是砝码放置的位置有左右之分,可以左面的减去右面的,也可以右面的减去左面的。同理,再求出y为最小合法正值时x的解,将这两种情况比较取小的即可。
#include
#include
#include
#include
using namespace std;
#define ll long long
int exgcd(ll a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
return d;
}
int main()
{
int a,b,d,x,y;
while(~scanf("%d %d %d",&a,&b,&d))
{
if(!a&&!b&&!d) break;
int d1=exgcd(a,b,x,y);
x=x*d/d1;
y=y*d/d1;
int xx1=(x%(b/d1)+b/d1)%(b/d1);
int yy1=(d-xx1*a)/b;
yy1=fabs(yy1);
int sum=xx1+fabs(yy1);
int yy2=(y%(a/d1)+a/d1)%(a/d1);
int xx2=(d-yy2*b)/a;
xx2=fabs(xx2);
if(sum>xx2+yy2) printf("%d %d\n",xx2,yy2);
else printf("%d %d\n",xx1,yy1);
}
return 0;
}