2018.5.26 T1新田忌赛马

新田忌赛马

【问题描述】

(注:此题为d2t2-难度)
田忌又在跟大王van赛马的游戏
田忌与大王一共有2*n匹马,每个马都有一个能力值x,1<=x<=2*n且每匹马的x互不相同。每次田忌与大王放出一匹马,较大的获胜。但是田忌有一个能力,在任何比赛的开始前,他可以把马变成x较小的获胜,并一直持续到比赛结束
田忌可以一直不用这个能力,也可以在第一轮前使用
现在,田忌已经知道了大王的出马顺序,田忌要问聪明的你,他最多能获得几次胜利?

【输入格式】

第一行为一个整数:N(1<=N<=50000)接下来 一行n个数,为大王的顺序出场的n匹马的能力值(田忌的马可以通过此求出)

【输出格式】

一个整数,表示最多的获胜次数
【样例输入】
4
1
8
4
3

【样例输出】

3

【样例说明】

田忌第一次出能力为7的马获胜
第二次开始前使用能力,出能力为6的马获胜
第三次出能力为5的马失败
第四次出能力为2的马获胜
总共3次

【出题人的关怀】

乱搞出奇迹(雾)
大胆猜想,不要证明

【数据规模】

对于20%的数据,n<=10
对于40%的数据 n<=20
对于35%的数据,不使用能力也可获得最多胜利(即20个点中有7个点不使用能力的程序能过(雾))
前3个档的总分为60分(出题人的关怀)
对于80%的数据,n<=5000
对于100%的数据,n<=50000,


感谢yk daolao 出题
先看一看部分分吧

不使用能力就是普通的田忌赛马了,应该都会,
两边sort一下,如果当前最弱能打败对面最弱的,就打,不然打对面最强的。更正解没关系

80%,应该 O ( n 2 )
枚举使用能力的时间,将王的分成前后两段,前面尽量赢,后面尽量输,王每次要排序,sort会炸,用桶排就行了

正解,正反各做一遍dp,枚举分割线合并
此时策略是选大于对面的最小的出战,因为要考虑反向的dp,所以不能用普通的策略。
虽然正反dp时会重复计算一个数,但数是一一对应的,
所以一定会有另一个数将其贡献抵消
[原题](https://www.luogu.org/problemnew/show/P3129

#include <set>
#include <cstdio>
#include <bitset>
using namespace std;
const int N=5e5;
bitset<N> vis;
set<int> x,y;
int a[N],f[N],g[N];
int n,ans;
int main() {
//  freopen("horse.in","r",stdin);
//  freopen("horse.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),vis[a[i]]=1;
    for (int i=1;i<=n*2;i++) if (!vis[i]) x.insert(i),y.insert(2*n-i);
    for (int i=1;i<=n;i++) {
        set<int>::iterator z=x.upper_bound(a[i]);
        if (z!=x.end()) {
            x.erase(z);
            f[i]++;
        }
        f[i]+=f[i-1];
    }
    for (int i=n;i>=1;i--) {
        set<int>::iterator z=y.upper_bound(2*n-a[i]);
        if (z!=y.end()) {
            y.erase(z);
            g[i]++;
        }
        g[i]+=g[i+1];
    }
    for (int i=0;i<=n;i++) ans=max(ans,f[i]+g[i+1]);
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/80466018