【问题描述】

(注:此题为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 i\in [0,n])\),但这样显然是有重复的。

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

如图,对于一个\(i\),如果有一匹马\(mid\)被选了两次:\(f\)数组对\(l\),\(g\)数组对\(r\)。那么必定有一匹马没被\(f\)与\(g\)用过(多出来了),设其能力值为\(t\)。显然,\(t\notin[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;
}

最新文章

  1. jmap
  2. C++ 用libcurl库进行http通讯网络编程
  3. paypal api 相关资料
  4. MySQL(7):数值类型
  5. C语言初学 转义字符举例
  6. 栈应用之中缀表达式计算 MFC实现(计算器核心)
  7. spice for openstack
  8. Maven转化为Dynamic Web Module
  9. 第一周-JAVA基本概念
  10. iOS不能交互的几种情况
  11. Intent的Data和Type和Flag属性-amdroid学习之旅(五十一)
  12. Eclipse 手动增加linker library
  13. php 获得汇率(解析页面内容获得指定数据)
  14. 使用tinymce富文本
  15. 关于Access导入Oracle会产生双引号的问题
  16. MariaDB实现主从配置及读写分离(一)
  17. 在SELECT DISTINCT 状况下使用 Order BY Newid() 随机数选出记录
  18. 【校招面试 之 C/C++】第2题 函数模板、类模板、特化、偏特化
  19. BigDecimal 精准加减乘除
  20. 第七次作业PSP

热门文章

  1. QuantLib 金融计算——基本组件之 Money 类
  2. Can not issue data manipulation statements with executeQuery()的解决方案
  3. apache添加ssl协议实现用户认证
  4. groovy常用语法及实战
  5. Prometheus 基于文件的服务发现
  6. python利用dijkstra算法求解图中最短距离
  7. 『线段树及扫描线算法 Atlantis』
  8. (7)ASP.NET Core 中的错误处理
  9. j.u.c: Java并发包的5大块
  10. Java自学-数字与字符串 格式化输出