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;
}