[HNOI2007]梦幻岛宝珠 DP+折半
程序员文章站
2024-03-20 18:16:22
...
Description
给你N颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过W,并输出最大的总价值。
Sample Input
4 10
8 9
5 8
4 6
2 5
4 13
8 9
5 8
4 6
2 5
16 75594681
393216 5533
2 77
32768 467
29360128 407840
112 68
24576 372
768 60
33554432 466099
16384 318
33554432 466090
2048 111
24576 350
9216 216
12582912 174768
16384 295
1024 76
-1 -1
Sample Output
14
19
1050650
我们考虑折半一下。
将b大于15次方的数变成,然后折半去做DP。
我们发现这样空间和时间都会炸锅。
于是我们可以调整一下折半的分界线,我调到10就过了。(感觉我是卡过去的)
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 9 * ((1 << 16) - 1);
LL _max(LL x, LL y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct node {
int a, b, v;
} w1[110], w2[110]; int n1, n2;
int bin[30];
LL f1[1000000], f2[550000];
int main() {
bin[0] = 1; for(int i = 1; i <= 30; i++) bin[i] = bin[i - 1] * 2;
while(1) {
int n = read(), m = read();
if(n == -1 && m == -1) break;
n1 = n2 = 0; int s1 = 0, s2 = 0;
for(int i = 1; i <= n; i++) {
int w = read(), v = read();
int b = 0;
while(w % 2 == 0) w /= 2, ++b;
if(b > 10) w1[++n1].a = w, w1[n1].b = b - 11, w1[n1].v = v, s1 += w1[n1].a * bin[w1[n1].b];
else w2[++n2].a = w, w2[n2].b = b, w2[n2].v = v, s2 += w2[n2].a * bin[w2[n2].b];
} memset(f1, -1, sizeof(f1));
f1[0] = 0; s1 = _min(s1, m / bin[11]);
for(int i = 1; i <= n1; i++) {
int c = w1[i].a * bin[w1[i].b];
for(int j = s1 - c; j >= 0; j--) if(f1[j] != -1){
f1[j + c] = _max(f1[j + c], f1[j] + w1[i].v);
}
} memset(f2, -1, sizeof(f2));
f2[0] = 0;
for(int i = 1; i <= n2; i++) {
int c = w2[i].a * bin[w2[i].b];
for(int j = s2 - c; j >= 0; j--) if(f2[j] != -1){
f2[j + c] = _max(f2[j + c], f2[j] + w2[i].v);
}
} LL ans = 0;
for(int i = 0; i <= s2; i++) f2[i] = _max(f2[i], f2[i - 1]);
for(int i = 0; i <= s1; i++) {
if(m < (LL)i * bin[11]) break;
if(f1[i] != -1) ans = _max(ans, f1[i] + f2[_min(s2, m - i * bin[11])]);
} printf("%lld\n", ans);
}
return 0;
}
上一篇: Filter解决session 过期,跳转到登陆页面
下一篇: 理解 Web 中的Session