Solution - P2851 [USACO06DEC] The Fewest Coins G

背包玩完了……代码死于试图用单调队列大炮打蚊子的时候。

思路

多重背包叠完全背包。

代码

#include <bits/stdc++.h>
#define rint register int 
#define rllong register long long
#define llong long long
#define N 105
#define M 100005
using namespace std;

int dp1[M], dp2[M];
int que1[M], que2[M], he, ta;
int a[N], c[N], maxn, sum;
int n, m, ans = 1e9+7;

int main(){
	scanf("%d %d", &n, &m), maxn = m;
	for(rint i = 1; i <= n; ++i) scanf("%d", &a[i]), maxn = max(maxn, a[i]*a[i]+m);
	for(rint i = 1; i <= n; ++i) scanf("%d", &c[i]), sum += a[i]*c[i];
	if(sum < m){
		puts("-1");
		return 0;
	}
	for(rint i = 1; i <= maxn; ++i) dp1[i] = dp2[i] = 1e9+7;
	for(rint i = 1; i <= n; ++i){
		for(rint q = 0; q < a[i]; ++q){
			he = 1, ta = 0;
			for(rint d = 0; a[i]*d+q <= maxn; ++d){
				rint p = a[i]*d+q;
				while(he <= ta && d-que1[he] > c[i]) ++he;
				while(he <= ta && que2[ta]+(d-que1[ta]) >= dp1[p]) --ta;
				++ta, que1[ta] = d, que2[ta] = dp1[p];
				dp1[p] = min(dp1[p], que2[he]+(d-que1[he]));
			}
		}
	}
	for(rint i = 1; i <= n; ++i)
		for(rint j = a[i]; j <= maxn; ++j)
			dp2[j] = min(dp2[j], dp2[j-a[i]]+1);
	for(rint i = m; i <= maxn; ++i)
		ans = min(ans, dp1[i]+dp2[i-m]);
	printf("%d", ans>1e9 ? -1 : ans);
	return 0;
}

posted @ 2025-05-31 22:53  Hootime  阅读(12)  评论(0)    收藏  举报