【贪心】【2018.10.1提高组模拟】T1(WOJ 2687) 卡牌游戏

题目(卡牌游戏):

【题目描述】  

L最近喜欢上了一个卡片游戏,游戏规则是: 2个人一共拿2n张卡片,编号1..2n,每个人n张,然后进行n轮出牌,每轮2个人都打一张牌,,点数大的玩家每次获1分

L可以预测到对方要打牌的顺序。

同时,L有一次机会选择了某个时间点,从那个时候开始,每回合点数少者获胜。

请你帮助L获得最大的分数

【输入】

第一行是1个整数n

接下来n行表示,对手每次的出牌,根据这些数字,你一定知道了L手上的牌的吧

【输出】

1个整数,表示L能获得最高分数

【样例输入】

4
1
8
4
3                            

【样例输出】

9

42

【数据范围】

对于 20%:N<=10

对于 50%:N<=100

对于另外 20%:K = 0

对于 100%:1 <= N <= 100000,0 <= K <= N,M <= 10^14,1 <= b[i] <= a[i] <= 10^9

分析:

一、对 30%数据 

枚举每一个位置作为时间点,设第 i 个点为分割点。

利用田忌赛马的贪心策略,对于前面 1~i-1 的数字从大到小排序,后面的从小到大排序 用自己最大的牌与前面最大的比较,如果能胜利则 ans++,且丢掉自己的一张牌 用自己最小的牌与后面最小的比较,如果能胜利则 ans++,且丢掉自己的一张牌
 
 
二对于 100%的数据 

贪心部分与 30 分数据差不多 但找分割点,可以 set,把自己的卡片加入到 set,每次拿正好 大一点的数,用完删除 正着做一次,反着做一次,然后选一次每个点作为分割点的得分

代码:

#include<bits/stdc++.h>
using namespace std;
set<int> l,r;
#define N 50010
int a[N],g[N],f[N],n,w[N*2],ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		w[a[i]]=1;
	}
	for(int i=1;i<=2*n;i++){
		if(w[i]==0){
			l.insert(-i);
			r.insert(i);
		}
	}
	for(int i=1;i<=n;i++){
		set<int>::iterator it=r.upper_bound(a[i]);//r中第一个比a[i]大的数
		if(it!=r.end()){
			r.erase(*it);
			f[i]=f[i-1]+1;
		} 
		else f[i]=f[i-1];
	}
	for(int i=n;i>=1;i--){
		set<int>::iterator it=l.upper_bound(-a[i]);
		if(it!=l.end()){
			l.erase(*it);
			g[i]=g[i+1]+1;
		} 
		else g[i]=g[i+1];
	}
	for(int i=0;i<=n;i++)
		ans=max(ans,f[i]+g[i+1]);
	cout<<ans;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_42754826/article/details/82917310