1. 程式人生 > >【貪心】【2018.10.1提高組模擬】T1(WOJ 2687) 卡牌遊戲

【貪心】【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;
}