【中山市选2011】辽哥游戏

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值