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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值