[bzoj4391]高分低分——贪心

题目大意:

贝西很喜欢玩一种纸牌游戏。
贝西和她的朋友艾尔西正在玩这个简单的纸牌游戏。游戏有2N张牌,牌上的数字是1到2N。把这些牌分成两份,贝西有N张,艾尔西有另外N张。接下来她们进行N轮出牌,每次各出一张牌。一开始,谁出的牌上的数字大,谁就获得这一轮的胜利。贝西有一个特殊权利,她可以在任意一个时刻把原本数字大的获胜的规则改成数字小的获胜,这个改变将会一直持续到游戏结束。特别的,贝西可以从第一轮开始就使用小牌获胜的规则,也可以直到最后一轮都还杂使用大牌获胜的规则。
现在,贝西已经知道了艾尔西出牌的顺序,她想知道她最多能够赢多少轮。

思路:

考虑只比大的情况,肯定是贪心地每次选恰好大于对面出的卡,只比小的同样。
现在又有比大又有比小,但是我们仍然按照这个策略去出牌,不难发现这样可能会在前面把后面满足情况的卡给出掉,假设目前出的卡为a,这种情况下一定会有没有出的卡b>a,所以我们只需要后悔一下,在前面出b就好了。
于是我们可以分别对每一个前缀和后缀求比大和比小的时候的答案,枚举分割点即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
typedef long long ll;

using namespace std;

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

void File(){
    freopen("bzoj4391.in","r",stdin);
    freopen("bzoj4391.out","w",stdout);
}

const int maxn=5e4+10;
int n,a[maxn],f[maxn],g[maxn],ans;
bool bel[maxn<<1];
set<int>s;
set<int>::iterator it;

void init(){
    read(n);
    REP(i,1,n){
        read(a[i]);
        bel[a[i]]=1;
    }
}

void work(){
    REP(i,1,n<<1)if(!bel[i])s.insert(i);
    REP(i,1,n){
        it=s.lower_bound(a[i]);
        if(it==s.end()){
            f[i]=f[i-1];
            continue;
        }
        f[i]=f[i-1]+1;
        s.erase(it);
    }
    s.clear();
    REP(i,1,n<<1)if(!bel[i])s.insert(i);
    DREP(i,n,1){
        it=s.lower_bound(a[i]);
        if(it==s.begin()){
            g[i]=g[i+1];
            continue;
        }
        --it;
        g[i]=g[i+1]+1;
        s.erase(it);
    }
    REP(i,0,n)ans=max(ans,f[i]+g[i+1]);
    printf("%d\n",ans);
}

int main(){
    File();
    init();
    work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值