【NOIP校内模拟/Usaco2015 dec—High Card Low Card】cardgame
【题意】
L最近喜欢上了一个卡片游戏,游戏规则是: 2 个人一共拿 2n 张卡片,编号 1..2n,每个人 n 张,然后进行 n 轮出牌,每轮 2 个 人都打一张牌,,点数大的玩家每次获 1分。 L可以预测到对方要打牌的顺序。 同时,L有一次机会选择了某个时间点,从那个时候开始,每回合点数少者获胜。
请你帮助 L获得最大的分数
我们用贪心来做
假设规则没有变的时候 对于对方打出的一张牌 L从他的牌里打出一张刚好比这张牌大的牌显然是最优的
假设规则变了的时候 对于对方打出的一张牌 L从他的牌里打出一张刚好比这张牌小的显示是最优的
似乎这个地方也有另一种贪心的方法 对于每一张牌 找一个最大的比他的牌也是可行的 因为这样在变规则后 可以使得剩下的牌更好得分
我们考虑如何实现
我们维护两个数组 front back,front[i]:没变规则时,1~i轮能得到的最大分数 back[i]:变了规则后,i~n轮能得到的最大分数
答案为max{front[i]+back[i+1]}
很多人都会提到说 可能一张牌在点数大的赢的时候被用了,后面改规则后也被用了,就被重复用了两次。
但是其实没有关系。如果一张牌a被用了两次,那么就说明手中有一张牌设为b没有被用过。若a>b,那么在点数小的赢那轮可以用b去替代a来赢得胜利;反之亦然。
最后 数组记得开100000 不然会炸成30分
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,cnt;
int t[N],card[N],sx[N];
int front[N],back[N];
bool used[N];
int find_upper(int x)
{
int l=0,r=n;
while(l<=r)
{
int m=(l+r)>>1;
if(card[m]>x) r=m-1;
else l=m+1;
}
return l;
}
int find_lower(int x)
{
int l=0,r=n;
while(l<=r)
{
int m=(l+r)>>1;
if(card[m]>x) r=m-1;
else l=m+1;
}
return l-1;
}
int main()
{
freopen("cardgame.in","r",stdin);
freopen("cardgame.out","w",stdout);
memset(used,false,sizeof(used));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>sx[i];
t[sx[i]]++;
}
for(int i=1;i<=2*n;i++)
{
if(!t[i]) card[++cnt]=i;
}
for(int i=1;i<=n;i++)
{
int pos=find_upper(sx[i]);
while(used[pos]==true) pos++;
if(pos>n) front[i]=front[i-1];
else
{
used[pos]=true;
front[i]=front[i-1]+1;
}
}
//for(int i=1;i<=n;i++) cout<<front[i]<<" ";
memset(used,false,sizeof(used));
for(int i=n;i>=1;i--)
{
int pos=find_lower(sx[i]);
while(used[pos]==true) pos--;
if(pos<1) back[i]=back[i+1];
else {
used[pos]=true;
back[i]=back[i+1]+1;
}
}
//for(int i=1;i<=n;i++) cout<<back[i]<<" ";
int ans=0;
for(int i=0;i<=n;i++)
{
ans=max(front[i]+back[i+1],ans);
}
cout<<ans;
return 0;
}
QQ40523591~欢迎一起学习交流~