PC/UVa 110707/10090

c1美元的盒子可以装n1个弹珠,c2美元的盒子可以装n2 个弹珠,一共n个弹珠问怎样花最少的钱将盒子装满弹珠,且不留弹珠

一看没思路,再看,可能是跟线性同余方程有关,

欧几里得扩展算法

a*x+b*y=gcd(a,b)

b*x1+(a-floor(a/b)*b)y1=gcd(a,b);

将算式扩展开可得

x=y1;

y=x1-floor(a/b)*y1;

求出 一个x0 y0使得 a*x0+b*y0=gcd(a,b);在这里要说明一点,如果方程 a*x+b*y=n有解,则n|(gcd(a,b));

则 a*x*n/gcd(a,b)+b*y0*n/gcd(a,b)=n;

则 x=x0*n/gcd(a,b)  y=y0*n/gcd(a,b); 为方程的一组解

如果方程有解,则又无数解

m1=x+b*t   m2=y-a*t;

t 可以任意,如果不知道怎么推出的话,就把它带进去,就知道了

再回到题目中,现在求出方程n1*x+n2*y=n的一组解 x0 y0

x=x0+t*n2  y=y0-t*n1;

又由于题中都为非负数

x>=0  y>=0从而求出t的范围

t1>=(-x0*n/g)/n2//上取整

t2<=(y0*n/g)/n1//下取整

c1*x+c2*y=num+t(c1*n2-c2*n1);

如果c1*n2-c2*n1>0 t=t1

否则  t=t2

到这里基本上就可以求出此题的大部分,但是有一个细节要注意一下//我在这道题上最主要的搞出来了,但是就是范围老是出错,你要小心哦

200

10 20

20 20

200

20 20

10 20

如果这两组数据你能过得话基本上你就可以AC了

 

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
long n1,n2,c1,c2;
long n;
long gcd(long a,long b,long &x,long &y)
{
 long g,x1,y1;
 if(b==0)
 {
  x=1;
  y=0;
  return a;
 }
 if(b>a)
 {
  g=gcd(b,a,y,x);
 }else
 {
  g=gcd(b,a%b,x1,y1);
  x=y1;
  y=x1-(a/b)*y1;
 }
 return g;
}
int main()
{
 long t1,t2,x,y,x0,y0,g,t;
 while(scanf("%ld",&n)!=EOF)
 {
  if(n==0) break;
  scanf("%ld%ld%ld%ld",&c1,&n1,&c2,&n2);
  g=gcd(n1,n2,x0,y0);
  t1=ceil((-1.0*x0*n)/n2);
  t2=floor((1.0*y0*n)/n1);
  if(t1>t2||n%g!=0)
  {
   printf("failed\n");
   continue;
  }
  if(c1*n2-c2*n1>0)
   t=t1;
  else
   t=t2;
  x=x0*n/g+n2*t/g;
  y=y0*n/g-n1*t/g;
  printf("%ld %ld\n",x,y);
 }
 return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值