【貪心】【2018.10.1提高組模擬】T1(WOJ 2687) 卡牌遊戲
阿新 • • 發佈:2018-12-13
題目(卡牌遊戲):
【題目描述】
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; }