Cerc2014 The Imp

Cerc2014 The Imp

第一行有两个数字N,K,表示有N个物体,接下来每个物体有2个描述权值Vi, Ci,表示该物体的价值和价格。商家很坑,他有K次机会用魔法使得你买完物品之后就立马让你买的该物品消失(但已经付了钱),而商家的目标则是使得你的净收入尽量低。你可以无限量买东西(每种只能拿一个),但最后只能带走一件物品,不过当然想要使得净收入尽量高。在双方皆采取最佳策略的情况下,你最多能得到多少钱?(当然,你也可以什么都不买) 净收入是总最后的物品价值减去总支出

范围

       N <= 1500000, k <=9

题解

       我们把问题转化一下,我们不是每次买对方一个物品,而是直接把策略(s1,s2…sk+1)全部告诉对方,这对于对方和我们都没什么,因为双方都保证是最优策略了

       对于我们的买东西的最优策略(s1,s2…sk+1)(可以少于k+1件),我们可以证明V(si)<V(si+1),假如V(si)>V(si+1),我们交换这两个,无论对方怎么操作,都会得到更坏的结果,这个应该很显然吧,因为如果V(si)>V(si+1)那么对方肯定会让你拿走si+1,可是如果交换之后无论对付对方让你拿走i或者i+1总收入都会高一些。

       所以我们先按V排序,定义F[i][j]表示j…n中选择,对方最多使用i次魔法的最高收益。

如果我们从j开始拿物品,那就有两种情况

直接给我们,那么收益就是Vj-Cj,

摧毁它,那么收益就是F[i-1][j+1]-Cj

      如果我们不拿j,那么就等于F[i][j+1]

综上f[i][j]= max(f[i][j + 1]; min(V(i) -C(i);-C(i)+ f[i - 1][j + 1])).

答案就是F[k][0](不一定用了k次魔法)


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define max(a, b) ((a)>(b)?(a):(b))
using namespace std;

const int maxn = 1510000;
const int maxm = 10;
const int inf = 9999999;
int f[maxm][maxn], n, m;
pair<int, int> a[maxn];
void init(){
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i ++)
		scanf("%d%d", &a[i].first, &a[i].second);
}
void work(){
	sort(a, a + n); f[0][n] = -inf;
	for (int i = n - 1; i >= 0; i --)
		f[0][i] = max(a[i].first - a[i].second, f[0][i + 1]);
	for (int i = 1; i <= m; i ++){
		f[i][n] = -inf;
		for (int j = n - 1; j >= 0; j --){
			int tmp = min(a[j].first - a[j].second, -a[j].second + f[i - 1][j + 1]);
			f[i][j] = max(tmp, f[i][j + 1]);
		}
	}
	printf("%d\n", max(0, f[m][0]));
	
}
int main(){
	int T = 0;
	scanf("%d", &T);
	while (T --) init(), work();
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值