一本通 提高篇 10179. Banknotes.

https://loj.ac/p/10179

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <deque>

using namespace std;
/*
https://loj.ac/p/10179

题目描述
原题来自:POI 2005
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有 n 种面值的硬币,
面值分别为 b_1, b_2,~~~ , b_n。但是每种硬币有数量限制,
现在我们想要凑出面值 k,求最少要用多少个硬币。

输入格式
第一行一个数 n;

接下来一行 n 个整数 b_1, b_2,~~~ , b_n;

第三行 n 个整数 c_1,c_2,~~~ ,c_n,表示每种硬币的个数;

最后一行一个数 k,表示要凑的面值数。

输出格式
第一行一个数表示最少需要付的硬币数。

样例
输入
3
2 3 5
2 2 1
13
输出
3
数据范围与提示
对于全部数据,1<= n<= 200,1<= b_1<= b_2<= ~~ <= b_n<= 2 * 10^4,1<= c_i,k<= 2 * 10^4。


3
300 700 4800
10000 10000 10000
5000

3
3   7   48
100 100 100
50


*/

const int N = 20010;
int b[N], c[N];
int dp[205][N];
int n;
int k;
//多重背包 单调队列优化  todo
int main()
{
	memset(dp, 0x3f, sizeof dp);
	dp[0][0] = 0;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> b[i];
	}
	for (int i = 1; i <= n; i++) {
		cin >> c[i];
	}
	cin >> k;
	
	for (int i = 1; i <= n; i++) {
		int dd = 0;
		for (int j = 0; j < b[i]; j++) {
			deque<int> q;
			dp[i][j] = dp[i - 1][j];
			for (int p = j; p <= k; p += b[i]) {
				while (!q.empty() && p-b[i]*c[i] > q.front()) q.pop_front();
				while (!q.empty() && dp[i - 1][q.back()] + (p-q.back())/b[i] >= dp[i - 1][p]) q.pop_back();
				q.push_back(p);
				dp[i][p] = min(dp[i][p], dp[i - 1][q.front()] + (p - q.front()) / b[i]);
				
			}
		}
		//cout << dp[i][k] << ". i=" <<i<<",k=" << k << endl;
	}

	cout << dp[n][k] << endl;

	return 0;
}

posted on 2024-06-23 00:52  itdef  阅读(4)  评论(0编辑  收藏  举报

导航