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