bzoj4391 [Usaco2015 dec]High Card Low Card题解

这道题算是见过奶牛题里面最难的。。是我见识太少了

绕了一大圈,问了Q巨才明白这题怎么做

下面是Q巨原话

 先考虑前i张牌,并且是大的赢

那么我们就用尽可能小的能赢对面的牌来打

然后扫一遍就可以知道i=0,1,2,3,...,n时最多能赢多少

同理倒着扫一遍小的赢的情况……然后枚举分割线 

but……这样做的话可能会出现,一张牌被用了多次的情况……但是不怕……省下来的牌总是可以代替这些被用了多次的牌来得到胜利


很有道理是不是,然后维护两个set正反跑贪心


orz Q巨&&Claris


//Copyright(c)2016 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
inline void splay(int &v){
	v=0;char c=0;int p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
#include<set>
set<int>s,t;
int a[200010],b[200010];
int f[200010],g[200010];
int main(){
	freopen("xxx.in","r",stdin);
	freopen("xxx.out","w",stdout);
	int n;splay(n);
	for(int i=1;i<=n;i++)splay(a[i]),b[a[i]]=true;
	for(int i=1;i<=n<<1;i++){
		if(!b[i]){
			s.insert(i);
			t.insert(-i);
			//cerr<<i<<endl;
		}
	}
	for(int i=1;i<=n;i++){
		set<int>::iterator it=s.lower_bound(a[i]);
		if(it!=s.end())s.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=t.lower_bound(-a[i]);
		if(it!=t.end())t.erase(it),g[i]=g[i+1]+1;
		else g[i]=g[i+1];
	}
	int ans=0;
	for(int i=0;i<=n;i++){
		ans=max(ans,f[i]+g[i+1]);
	}
	printf("%d\n",ans);
}


你可能感兴趣的:(题解)