bzoj4391 [Usaco2015 dec]High Card Low Card

传送门

分析

神奇的贪心,令f[i]表示前i个每次都出比对方稍微大一点的牌最多能赢几次

g[i]表示从i-n中每次出比对方稍微小一点的牌最多赢几次

ans=max(f[i]+g[i+1]) 0<=i<=n

虽然方案可能会重合但是这是可行的

1:因为限制比原题目宽,所以ans>=真实的答案

2:对于重复取的数a,如果集合中有个没取的数<a,那么在用小的赢的时候可以代替a

如果>a,那么在用大的赢时可以代替a

用set来记录最接近的数

代码

#include<bits/stdc++.h>
using namespace std;
set<int>a,b;
int f[100100],g[100100],is[100100],d[100100]; 
int main(){
    int n,m,i,j,k;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
      scanf("%d",&d[i]);
      is[d[i]]=1;
    }
    for(i=1;i<=2*n;i++)
      if(!is[i]){
        a.insert(i);
        b.insert(-i);
      }
    for(i=1;i<=n;i++){
      set<int>::iterator pl=a.lower_bound(d[i]);
      if(pl!=a.end())a.erase(pl),f[i]=f[i-1]+1;
        else f[i]=f[i-1];
    }
    for(i=n;i>0;i--){
      set<int>::iterator pl=b.lower_bound(-d[i]);
      if(pl!=b.end())b.erase(pl),g[i]=g[i+1]+1;
        else g[i]=g[i+1];
    }
    int Ans=0;
    for(i=0;i<=n;i++)Ans=max(Ans,f[i]+g[i+1]);
    cout<<Ans<<endl;
    return 0;
}
posted @ 2019-02-09 15:11  水题收割者  阅读(152)  评论(0编辑  收藏  举报