现在的位置: 首页 > 综合 > 正文

Cerc2014 The Imp

2017年10月16日 ⁄ 综合 ⁄ 共 1501字 ⁄ 字号 评论关闭

题目大意:有n种物品,Imp有k次魔法,每个物品有一个价值v与一个价格p,你每次可以选择一个物品买下来,Imp则可以用一次魔法把物品变没,直到某一次Imp没有用魔法,那么你就可以把这件物品带走,你的收益就是这个物品的价值减去所有你选的物品的价格,假设你和Imp都是最优策略,问最多的收益是多少   n<=150000 k<=9 v<=1000000 p<=1000000

首先你买的物品的价值是单调增的,如果有两个物品vi<=vj,你先买i再买j的最小收益是min(vi-pi,vj-pi-pj) ,但是如果你先买j再买i最小收益就是min(vj-pj,vi-pi-pj) ,因为vi-pi-pj比vi-pi与vj-pi-pj都小,所以min(vj-pj,vi-pi-pj)<=min(vi-pi,vj-pi-pj),所以先买i再买j肯定不会变差。

于是我们先把物品按价值从小到大排序,于是就可以Dp了

设f[i][j]代表从第i~n个中选,Imp只用不超过j次魔法的最大收益

显然f[i][0]=max(f[i+1][0],v[i]-p[i]);   

 如果j不等于0时  先算正好用j次魔法的  首先你可以选择不买->f[i][j]=f[i+1][j]。 如果你选择了买,那么决定权就在Imp手上了,如果他用魔法那就是f[i+1][j-1]-p[i],不用的话就直接是v[i]-p[i](此时只用了0次魔法,但是也可以更新f[i][j]) 。最后再用f[i][j-1]来更新,代表没有用满j次魔法  综上f[i][j]=min(f[i][j-1],max(f[i+1][j],min(v[i]-p[i],f[i+1][j-1]-p[i])))

这样,最后的答案就是max(f[1][m],0) 因为也可以一个都不买

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=150011,inf=~0u>>2;
struct tg{int v,p;}e[maxn];
inline void read(int &x){
	char ch=getchar();x=0;
	while (!isdigit(ch)) ch=getchar();
	for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
int n,m;
void init(){
	read(n); read(m);
	for (int i=1;i<=n;++i) read(e[i].v),read(e[i].p);
}
inline bool cmp(tg a,tg b){return a.v<b.v;}
int f[maxn][15];
void work(){
	sort(e+1,e+n+1,cmp); memset(f[n],200,sizeof(f[n])); f[n][0]=max(e[n].v-e[n].p,0); 
	for (int i=n-1;i>=1;--i){
		f[i][0]=max(f[i+1][0],e[i].v-e[i].p);
		for (int j=1;j<=m;++j) 
			f[i][j]=min(f[i][j-1],max(f[i+1][j],min(e[i].v-e[i].p,f[i+1][j-1]-e[i].p)));
	}
	cout<<max(f[1][m],0)<<endl;
}
int main(){
	int T; read(T); while (T--) init(),work();
	return 0;
}

抱歉!评论已关闭.