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;
}