• 20180527模拟赛T1——新田忌赛马


    【问题描述】

    (注:此题为d2t2-难度)

    田忌又在跟大王van赛马的游戏

    田忌与大王一共有2n匹马,每个马都有一个能力值x,1<=x<=2n且每匹马的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神犇的题解

    另外这位大佬在洛谷上也发了题解

    接下来是蒟蒻的题解:

    首先,回顾田忌赛马,我们发现tj是每次出比大王稍微快一些的马(如果有的话)。那么如果tj用了技能,他显然应该出比大王稍微慢一些的马。于是我们就可以很容易知道tj不用技能或是刚开始就用技能的最佳方案。

    我们令(f[i])表示前(i)个每次都出比对方稍微大一点的牌,最多能赢几次;(g[i])表示从([i,n])中每次出比对方稍微小一点的牌,最多赢几次。

    我们自然想到(ans = max(f[i]+g[i+1]mid iin [0,n])),但这样显然是有重复的。

    那么这样真的不可行吗?让我们冷静分析一下:

    如图,对于一个(i),如果有一匹马(mid)被选了两次:(f)数组对(l)(g)数组对(r)。那么必定有一匹马没被(f)(g)用过(多出来了),设其能力值为(t)。显然,(t otin[l,r])(不符合贪心规则)。不管这匹马在(l)左侧或是(r)的右侧,结果都是相同的。所以其实这个贪心思路是正确的。

    代码

    #include <cstdio>
    #include <cctype>
    #include <set>
    
    using namespace std;
    
    const int maxn = 50005;
    
    int f[maxn], g[maxn];
    int n;
    
    #define dd c = getchar()
    inline int read(int& x)
    {
    	x = 0;
    	char dd;
    	bool f = false;
    	for(; !isdigit(c); dd)
    	{
    		if(c == '-')
    			f = true;
    		if(c == EOF)
    			return EOF;
    	}
    	for(; isdigit(c); dd)
    		x = (x<<1) + (x<<3) + (c^48);
    	if(f) x = -x;
    	return 1;
    }
    #undef dd
    
    set<int> zheng, fan;
    set<int>::iterator z;
    
    int dw[maxn];
    bool whose[maxn<<1];
    
    inline void get()
    {
    	read(n);
    	for(int i = 1; i <= n; ++i)
    	{
    		read(dw[i]);
    		whose[dw[i]] = true;
    	}
    	for(int i = 1; i <= (n<<1); ++i)
    	{
    		if(!whose[i])
    		{
    			zheng.insert(i);
    			fan.insert((n<<1)-i);
    		}
    	}
    }
    
    int main()
    {
    	freopen("horse.in", "r", stdin);
    	freopen("horse.out", "w", stdout);
    	get();
    	for(int i = 1; i <= n; ++i)
    	{
    		z = zheng.upper_bound(dw[i]);
    		if(z != zheng.end())
    		{
    			f[i] = f[i-1] + 1;
    			zheng.erase(z);
    		}
    		else
    			f[i] = f[i-1];
    	}
    	for(int i = n; i >= 1; --i)
    	{
    		z = fan.upper_bound((n<<1)-dw[i]);
    		if(z != fan.end())
    		{
    			g[i] = g[i+1] + 1;
    			fan.erase(z);
    		}
    		else
    			g[i] = g[i+1];
    	}
    	int ans = 0;
    	for(int i = 0; i <= n; ++i)//注意从0开始,可以不用技能
    		ans = max(ans, f[i]+g[i+1]);
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    电子书下载:Pro jQuery
    神鬼传奇小技巧:教你如何修改自己想要的时装
    用虚拟机玩游戏的方法!! 开3D加速!
    如何让DevExpress的DateEdit控件正确显示日期的周名
    SOAP Version 1.2
    Delphi中的容器类
    <神鬼传奇>客户端终极优化精简方法
    今日阅读20090102基本数据结构
    判断一个char[]里是否包含两个连续的\r\n
    蛙蛙推荐:改进同步等待的网络服务端应用
  • 原文地址:https://www.cnblogs.com/pfypfy/p/9097134.html
Copyright © 2020-2023  润新知