UVa 10090 - Marbles
Published on 2016-03-02描述
有 个弹珠,你需要购买盒子将弹珠全部放进去(不允许有盒子空着)。有两种盒子:
- 第一种:价格 ,恰好装 个弹珠。
- 第二种:价格 ,恰好装 个弹珠。
你的任务就是求算出一种购买方案,使得把弹珠全部放入盒子的花销最小。如果不存在,输出 failed
。
样例输入
43 1 3 2 4 40 5 9 5 12 0
样例输出
13 1 failed
分析
这题还是独立想出来的,不错。
设第一种盒子买 个,第二种盒子买 个;第一种盒子能装 个价格 ;第二种盒子能装 个,价格 ,那么有:
当 或 时无解。
用扩展欧几里得算法求出一组满足方程的解 (但不一定满足题意,花费也不一定最小)。
我们知道这个方程有无数组解,扩展出更多解的方法是:
关键在于求取合适的 ,使得 既是整数,又花费最小。
设
算出 的取值范围,求解这个不等式组:
解出来是:
如果这个无整数 解,则输出 failed
。
我们接着计算出花费关于 的表达式:
设 这是个关于 的一次函数,显然 时,函数单调递增,取端点 。 时,函数单调递减,取端点 。
我之前是直接讨论斜率,没有明确弄出自变量的范围,导致 WA 半天找不出原因,看来运用常规数学处理方法才是简洁的,不易错的。
代码
// Created by Sengxian on 3/2/16. // Copyright (c) 2016年 Sengxian. All rights reserved. // UVa 10090 扩展 Eculid #include <algorithm> #include <iostream> #include <cassert> #include <cctype> #include <cstring> #include <cstdio> #include <cmath> #include <vector> using namespace std; typedef long long ll; inline int ReadInt() { int n = 0, ch = getchar(); while(!isdigit(ch)) ch = getchar(); while(isdigit(ch)) n = (n << 3) + (n << 1) + ch - '0', ch = getchar(); return n; } void extgcd(int a, int b, ll &x, ll &y) { if(b == 0) { x = 1, y = 0; }else { extgcd(b, a % b, y, x); y -= a / b * x; } } int n, a, b, c, d; int main() { while(n = ReadInt(), n) { c = ReadInt(), a = ReadInt(), d = ReadInt(), b = ReadInt(); int gcd = __gcd(a, b); ll x, y; if(n % gcd || n < min(a, b)) {puts("failed"); continue;} extgcd(a, b, x, y); x *= n / gcd, y *= n / gcd; ll deltaX = b / gcd, deltaY = a / gcd, delta = c * deltaX - d * deltaY; double l = ceil((double)-x / deltaX), r = floor((double)y / deltaY); if(l > r) {puts("failed"); continue;} if(delta > 0) x += l * deltaX, y -= l * deltaY; else x += r * deltaX, y -= r * deltaY; printf("%lld %lld\n", x, y); } return 0; }
附加输入
1791 2000000000 13 1 21 1791 1 21 10 13 1791 10 21 1 13 1791 1 13 10 21 1791 10 13 1 21 1 10 3 1 2 1 1 2 10 3 0
附加输出
15 76 76 15 11 120 120 11 15 76 failed failed