【2018/10/01测试T1】【WOJ 2687】卡牌游戏

【题目】

题目描述:

L最近喜欢上了一个卡片游戏,游戏规则是: 2 个人一共拿 2n 张卡片,编号 1……2n,每个人 n 张,然后进行 n 轮出牌,每轮 2 个人都打一张牌,点数大的玩家每次获 1 分

L 可以预测到对方要打牌的顺序。

同时,L 有一次机会选择了某个时间点,从那个时候开始,每回合点数少者获胜。

请你帮助L获得最大的分数

输入格式:

第一行是 1 个整数 n

接下来 n 行表示,对手每次的出牌,根据这些数字,你一定知道了 L 手上的牌的吧

输出格式:

1 个整数,表示 L 能获得最高分数

样例数据:

输入

4
1
8
4
3

输出

3

 

【分析】

对于 30% 数据:

枚举每一个位置作为时间点,设第i个点为分割点。 

田忌赛马的贪心策略,对于前面 1~i-1 的数字从大到小排序,后面的从小到大排序 

用自己最大的牌与前面最大的比较,如果能胜利则 ans++,且丢掉自己的一张牌 

用自己最小的牌与后面最小的比较,如果能胜利则 ans++,且丢掉自己的一张牌 


对于 100% 的数据:

贪心部分与 30分数据差不多 

关键是找分割点,可以用数组排序,也可以 set,把自己的卡片加入到set,每次拿正好大一点的数,用完删除

正着做一次,反着做一次,然后选一次每个点作为分割点的得分 

 

【代码】

#include
#include
#include
#include
#define N 50005
using namespace std;
setl,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::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::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;
}

 

你可能感兴趣的:(#,模拟,模拟)