Description:
张辽是一个长发飘飘的非常聪明的男孩,人人都称他为“辽哥”。辽哥喜欢玩一个有趣的电脑游戏。这个游戏开始的时候有n个碉堡,每个碉堡拥有一个防御值和一个附加值。玩家拥有一个初始的攻击力。如果玩家破坏了一个碉堡,则他能得到1分。每一次,辽哥会选择一个碉堡进行攻击。所有未被破坏的碉堡会联合起来防御,因此为了破坏那个碉堡,辽哥的攻击力必须大于或者等于所有未被破坏的碉堡的防御值之和,否则辽哥就会输掉游戏。如果辽哥成功破坏了那个碉堡,那么他的攻击力会变成那个碉堡的附加值,然后他可以选择下一个攻击的目标。
由于辽哥拥有强大的编程能力,他不费吹灰之力就改写了那个游戏。在游戏开始前,他可以用炸弹消灭任意的碉堡,但是他不能通过这种方式来获得分数。问题来了,在游戏开始后,辽哥可以得到的最大分数是多少?
1<=T<=100,1<=n<=1000
题解:
可以感受到这种题是按某个顺序排序,然后就可以顺着做了。
对于一组方案,上下的顺序应该是可以调整的。
假设是a[i],b[i],a[j],b[j]
g是j以下的防御值和。
目前可以,有
b[i]>=g+a[j]
不可以交换,则有
b[j]<g+a[i]
想办法把g消掉。
g+a[i]−(g+a[j])>b[j]−b[i]
a[i]−a[j]>b[j]−b[i]
a[i]+b[i]>a[j]+b[j]
因此按照a+b的顺序排个序,后面直接 O(Tn2) dp就好了。
Code:
#include<cstdio>
#include<set>
#include<algorithm>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 1e3 + 5;
int n, m;
struct node {
int u, v;
} a[N];
int o, f[N], d[N], bz;
bool rank(node a, node b) {
return a.u + a.v < b.u + b.v;
}
int mi;
int main() {
while(scanf("%d", &n) != EOF) {
fo(i, 1, n) scanf("%d %d", &a[i].u, &a[i].v);
scanf("%d", &m);
sort(a + 1, a + n + 1, rank);
bz = 1;
fo(i, 1, n) if(a[i].u <= m) bz = 0;
if(bz) {
printf("0\n");
continue;
}
o = 0;
fo(i, 1, n) f[i] = a[i].u;
fo(j, 2, n) {
mi = 2e9;
fo(i, 1, n) {
int x = f[i];
if(mi <= a[i].v) f[i] = mi; else f[i] = 2e9;
mi = min(mi, x);
}
bz = 0;
fo(i, 1, n) {
f[i] += a[i].u;
if(f[i] <= m) bz = 1;
}
if(!bz) {
printf("%d\n", j - 1);
break;
}
}
bz = 0; fo(i, 1, n) if(f[i] <= m) bz = 1;
if(bz) printf("%d\n", n);
}
}