【题目】
题目描述:
L最近喜欢上了一个卡片游戏,游戏规则是: 2 个人一共拿 张卡片,编号 1……
,每个人
张,然后进行
轮出牌,每轮 2 个人都打一张牌,点数大的玩家每次获 1 分
L 可以预测到对方要打牌的顺序。
同时,L 有一次机会选择了某个时间点,从那个时候开始,每回合点数少者获胜。
请你帮助L获得最大的分数
输入格式:
第一行是 1 个整数
接下来 行表示,对手每次的出牌,根据这些数字,你一定知道了 L 手上的牌的吧
输出格式:
1 个整数,表示 L 能获得最高分数
样例数据:
输入
4
1
8
4
3
输出
3
【分析】
对于 30% 数据:
枚举每一个位置作为时间点,设第i个点为分割点。
田忌赛马的贪心策略,对于前面 1~i-1 的数字从大到小排序,后面的从小到大排序
用自己最大的牌与前面最大的比较,如果能胜利则 ++,且丢掉自己的一张牌
用自己最小的牌与后面最小的比较,如果能胜利则 ++,且丢掉自己的一张牌
对于 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;
}