Jzoj2309 辽哥游戏

227 篇文章 3 订阅
153 篇文章 0 订阅
 张辽是一个长发飘飘的非常聪明的男孩,人人都称他为“辽哥”。辽哥喜欢玩一个有趣的电脑游戏。这个游戏开始的时候有n个碉堡,每个碉堡拥有一个防御值a和一个附加值b。玩家拥有一个初始的攻击力S。如果玩家破坏了一个碉堡,则他能得到1分。每一次,辽哥会选择一个碉堡进行攻击。所有未被破坏的碉堡会联合起来防御,因此为了破坏那个碉堡,辽哥的攻击力必须大于或者等于所有未被破坏的碉堡的防御值之和,否则辽哥就会输掉游戏。如果辽哥成功破坏了那个碉堡,那么他的攻击力会变成那个碉堡的附加值,然后他可以选择下一个攻击的目标。

  由于辽哥拥有强大的编程能力,他不费吹灰之力就改写了那个游戏。在游戏开始前,他可以用炸弹消灭任意的碉堡,但是他不能通过这种方式来获得分数。问题来了,在游戏开始后,辽哥可以得到的最大分数是多少?

嗯,又是那种dp套贪心的题目了

先考虑如果知道破坏碉堡顺序,我们考虑如何最优

显然令f[i]表示一开始有i的能力的最优非常不方便转移

我们考虑令f[i]表示破坏i个碉堡需要的最小能力值,f[0]=0

那么,f[i]=f[i-1]+A[j](B[j]>=f[i-1]) O(N^2)暴力做即可,最后二分出最大的i满足f[i]<=S

好的现在来考虑如何排序

考虑两个状态i,i+1

i和i+1不能交换的充分条件:b[i+1]<a[i]+Σa[j] (j>i+1)

同时我们还有条件b[i]>=a[i+1]+Σa[j] (j>i+1)

两式相减得到:b[i+1]-b[i]<a[i]-a[i+1]

b[i+1]+a[i+1]<a[i]+b[i]

所以我们只需要按照a[i]+b[i]的顺序排序即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,f[1010];
struct p{ int a,b; } s[1010];
inline bool c1(p a,p b){ return a.a+a.b>b.a+b.b; }
int _18520(){
	if(~scanf("%d",&n)){
		for(int i=n;i;--i) scanf("%d %d",&s[i].a,&s[i].b);
		sort(s+1,s+1+n,c1); memset(f,0x3f,sizeof f); f[0]=0;
		for(int i=n;i;--i) for(int j=n;j;--j)
				if(s[i].b>=f[j-1]) f[j]=min(f[j],f[j-1]+s[i].a);
		scanf("%d",&m); 
		for(int t=n;~t;--t) if(f[t]<=m) return printf("%d\n",t);
	} return 0;
}
int main(){ while(_18520()); }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值