【2018/10/01測試T1】【WOJ 2687】卡牌遊戲
阿新 • • 發佈:2018-12-13
【題目】
題目描述:
L最近喜歡上了一個卡片遊戲,遊戲規則是: 2 個人一共拿 張卡片,編號 1……,每個人 張,然後進行 輪出牌,每輪 2 個人都打一張牌,點數大的玩家每次獲 1 分
L 可以預測到對方要打牌的順序。
同時,L 有一次機會選擇了某個時間點,從那個時候開始,每回合點數少者獲勝。
請你幫助L獲得最大的分數
輸入格式:
第一行是 1 個整數
接下來 行表示,對手每次的出牌,根據這些數字,你一定知道了 L 手上的牌的吧
輸出格式:
1 個整數,表示 L 能獲得最高分數
樣例資料:
輸入
4 1 8 4 3
輸出
3
【分析】
對於 30% 資料:
列舉每一個位置作為時間點,設第i個點為分割點。
田忌賽馬的貪心策略,對於前面 1~i-1 的數字從大到小排序,後面的從小到大排序
用自己最大的牌與前面最大的比較,如果能勝利則 ++,且丟掉自己的一張牌
用自己最小的牌與後面最小的比較,如果能勝利則 ++,且丟掉自己的一張牌
對於 100% 的資料:
貪心部分與 30分資料差不多
關鍵是找分割點,可以用陣列排序,也可以 set,把自己的卡片加入到set,每次拿正好大一點的數,用完刪除
正著做一次,反著做一次,然後選一次每個點作為分割點的得分
【程式碼】
#include<set> #include<cstdio> #include<cstring> #include<algorithm> #define N 50005 using namespace std; set<int>l,r; bool flag[N<<1]; int a[N],g[N],f[N]; int main() { // freopen("cardgame.in","r",stdin); // freopen("cardgame.out","w",stdout); int n,i,ans=0; scanf("%d",&n); memset(flag,true,sizeof(flag)); for(i=1;i<=n;++i) { scanf("%d",&a[i]); flag[a[i]]=false; } for(i=1;i<=(n<<1);++i) if(flag[i]) r.insert(i),l.insert(-i); for(i=1;i<=n;++i) { set<int>::iterator it=r.upper_bound(a[i]); if(it!=r.end()) { r.erase(*it); f[i]=f[i-1]+1; } else f[i]=f[i-1]; } for(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(i=0;i<=n;i++) ans=max(f[i]+g[i+1],ans); printf("%d\n",ans); // fclose(stdin); // fclose(stdout); return 0; }