2018-2-5超时错误更新:
使用宏#define min(a,b) (a)<(b)?(a):(b)时
在min()里面直接调用递归函数,会多出一次额外调用导致程序不会停止,现已更正
A New Year party is not a New Year party without lemonade! As usual, you are expecting a lot of guests, and buying lemonade has already become a pleasant necessity.
Your favorite store sells lemonade in bottles of n different volumes at different costs. A single bottle of type
i
has volume
You want to buy at least L liters of lemonade. How many roubles do you have to spend?
Input
The first line contains two integers n and L (1
The second line contains n integers
c1
,
c2
,
...
,
cn
(1
≤
ci
≤
109
) — the costs of bottles of different types.
Output
Output a single integer — the smallest number of roubles you have to pay in order to but at least L liters of lemonade.
题意:有
- 思路:把各店铺按单位毫升的价格(
ai2i−1 )排序,最划算的那家店铺自然是第一家。当 L÷ s[1].v 不能除尽时,余数部分的处理方法可能有 - 在第一家再买一杯
- 在不那么划算但一杯的价格便宜一点的第二家买足够的量
- 在第二家买一杯,还差的量在第三家买够
- …
动态规划思想就是用来解决这类问题的撒~
值得一提的是,当出现余数的时候,购买的果汁有一部分可能是不需要的,就导致每家店铺的划算程度发生改变,当前店铺可能不再是最优,所以需要尝试一下在其他店铺能不能组合除对于余数部分最优的方案。
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 30
#define min(a,b) (a)<(b)?(a):(b)
typedef long long ll;
//店铺类并重载<运算符
class store {
public:
ll vol;
ll cost;
bool operator<(store a) {
return (a.cost* vol > cost*a.vol);
}
}s[maxn + 5];
ll n, l;
//动态规划处理余数部分
ll ans(ll left,ll cost,int si) {
//以还差left毫升柠檬汁,已经花cost元的状态进入店铺si
//先尽可能在这家店购买
ll i = left / s[si].vol;//计算购买的杯数
cost += i*s[si].cost;//更新花费状态
left -= i*s[si].vol;//更新剩余量状态
//如果没有余数部分,则方案最优,直接返回
if (left == 0)return cost;
//如果已经是最后一家,就算柠檬汁会超出需要的量,但此时只能在这里购买
if (si == n)return cost + s[i].cost;
//处理余数部分:再买一杯超出需要的量或者去下一家店,两种取最少花费的那种
ll temp=ans(left, cost, si +1);
return min(cost + s[si].cost, temp);
}
int main() {
s[1].vol = 1;
cin >> n >> l;
cin >> s[1].cost;
for (int i = 2; i <= n; ++i) {
cin >>s[i].cost;
s[i].vol = 2 * s[i-1].vol;
}
sort(s+1, s + n+1);
ll tempm = 0;
ll left = l;
ll temp;
cout << ans(left, tempm, 1);
}