其他分享
首页 > 其他分享> > Cardgame

Cardgame

作者:互联网

题目背景
有一天 Alice 和 Bob 玩起了纸牌游戏。

他们一共有 \(2n\) 张纸牌,点数分别为 \(1,2,3,...,2n\),每个点数各一张,起初每人会被发到 n 张纸牌。

游戏一共有 \(n\) 轮,每轮 Alice 和 Bob 各出一张牌,谁的点数大谁就赢下了该轮。

但是 Alice 可以使用一次特权,在第 \(i\) 轮使用特权——“规则反转”,表示从第 \(i\) 轮到第 \(n\) 轮,双方玩家比拼谁的点数小,小的一方赢下那一轮。Alice可以在任何一轮使用该特权,当然 Alice 也可以从头到尾不使用该特权,亦或是从第 1 轮就开始使用。

换言之,一旦 Alice 在第 \(i\) 轮使用了特权,那么第 \(1\) 至 \(i−1\) 轮双方玩家比拼谁的点数大,第 \(i\) 至 \(n\) 轮双方玩家比拼谁的点数小。

现在给定 n,并给出 Bob n 轮打出的牌,询问 Alice 如何规划出牌和运用特权来赢取最多轮数。

输入格式
输入共 \(n+1\) 行。

第一行一个整数 n 。

接下来的 n 行每行一个在 \([1,2n]\) 范围内的正整数且各不相同,表示 Bob 每一轮出的牌的点数。

输出格式
输出一行一个整数表示 Alice 可能赢取的最多轮数。

样例
input

4
1
8
4
3

output

3

explanation
Alice 拥有的手牌是 \(2,5,6,7\)。她可以\(7,6,5,2\)这样出牌,并在第二轮使用特权。

数据范围
时间限制: 1s
空间限制: 256MB
对于 100% 的数据, \(n≤50000\)。

数据富含梯度。

把所有牌求出来后按照大小排序。不考虑特权,我们把Alice所有的牌放在一个set里,每次遇到Bob的牌找到一个最小的又比他大的,这样子就可以求出不使用特权的最多可能。

考虑使用特权,我们可以发现在\(i\)处使用特权,肯定是用前\(i\)大的放在前面,剩下的放在后面。那么其实我们按照刚刚的方法也可以预处理出只用前\(i\)大的最大赢的次数,是一个前缀和。同理,也可以求出一个后缀和有关用前\(i\)小的,然后加起来求个最小值就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N=50005;
set<int>s1,s2;
int n,v[N<<1],f[N],g[N],a[N],ans;
set<int>::iterator it;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i),v[a[i]]=1;
	for(int i=1;i<=(n<<1);i++)
	{
		if(!v[i])
		{
			s1.insert(i);
			s2.insert(-i);
		}
	}
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1],it=s1.lower_bound(a[i]);
		if(it!=s1.end())
		{
			f[i]++;
			s1.erase(it);
		}
	}
	for(int i=n;i>=1;i--)
	{
		g[i]=g[i+1],it=s2.lower_bound(-a[i]);
		if(it!=s2.end())
		{
			g[i]++;
			s2.erase(it);
		}
	}
	for(int i=0;i<=n;i++)
		ans=max(ans,f[i]+g[i+1]);
	printf("%d",ans);
	return 0; 
}

标签:Cardgame,int,s2,特权,Alice,点数,Bob
来源: https://www.cnblogs.com/mekoszc/p/16209534.html