落地成盒

1 篇文章 0 订阅

3 落地成盒 pdd.cpp / pdd.in / pdd.out 

3.1 题目描述 

众而周知,落地成盒是件很痛苦的事情,然而对于萌萌哒选手 pdd(不是 PDD)来说,只要有一种特 殊的技巧,就能避免落地成盒。 这个技巧便是:不停地往前跑,永远不要回头,永远不要往低处走。尴尬的是,当不能再往高处前进 时,pdd 还是不能避免成盒的命运。pdd 希望知道,自己最多能跑到多少地方。 整个地图可以抽象为长度为 n 的正整数序列 {ai},代表每个地方的高度。假设 pdd 在位置 i 处,那么 pdd 只能跑到 j 处(i < j,ai ≤ aj)。由于游戏有随机性,因此 pdd 不仅想知道他最多可能跑到多少地方, 还想知道从每个地方出发,他最多能跑到多少地方。 一句话题意:求出序列 {ai} 的最长不下降子序列的长度,以及以每个位置开头的不下降子序列的最长长度。

 3.2 输入

第一行输入一个整数 n,表示序列长度。 接下来一行输入 n 个整数,表示序列中的每个数。
3.3 输出
第一行输入一个整数 n,表示序列的长度。 接下来一行输入 n 个整数,表示以每个位置开头的不下降子序列的最长长度。
3.4 Special Judge 本题使用 Special Judge。 如果你完成了第一个任务,即第一行输出正确,你将获得 40% 的分数。 如果你完成了第二个任务,即第二行输出正确,你将获得 60% 的分数。 如果你能完成第二个任务,但不能完成第一个任务,请在第一行任意输出一个整数,否则将会错判。

3.5 样例 

3.5.1 输入 

1 4 2 8 5 7

3.5.2 输出 

4 3 3 1 2 1 5

3.5.3 解释 从 a1 = 1 出发,最长不下降子序列为 1 4 5 7 或者 1 2 5 7。 从 a2 = 4 出发,最长不下降子序列为 4 5 7。 从 a3 = 2 出发,最长不下降子序列为 2 5 7。 从 a4 = 8 出发,最长不下降子序列为 8。 从 a5 = 5 出发,最长不下降子序列为 5 7。 从 a6 = 7 出发,最长不下降子序列为 7。

3.6 数据规模与约定 对于 20% 的数据,n ≤ 20。 对于 50% 的数据,n ≤ 5×103。 对于 100% 的数据,n ≤ 106,ai ∈int。 3.7 提示 本题使用 Special Judge,将会忽略行末空格及文末回车。 请注意常数因子带来的程序效率上的影响

用的lower_bound,但还有点问题,艰难。

设h[i]为 长度为 i 的上升子序列的结尾元素的最小值。很明显,这个 h[i] 是个单调递增的数组。 
证明:如果h[i + 1] < h[i],那么长度为 i 的子序列可以索性不要 h[i] 这个元素,而是让 h[i + 1] 结尾,所以 h[i] 不会大于 h[i + 1]。 
如果有h[i] = h[i + 1],考虑长度为 i + 1的子序列是如何生成的。它必然是由长度为 i 的子序列加上一个更大的数组成的。现在长度为 i 的子序列的结尾的最小值为 h[i],那么长度为 i + 1 的子序列的结尾不可能等于 h[i],否则子序列就不是严格上升的了。 
因此 h[i] 是个单调递增的数组。

怎么求最长上升子序列的长度呢? 
很明显,如果我们按正确的算法操作下去,最后的答案就是 数组h 的大小。那怎么操作呢? 
如果 h.back() < num,就把 num 加入 h 的末尾(push_back);否则在 h 中二分查找,找到第一个大于等于 num 的数(lower_bound),把这个数改成 num。只要知道了 h[i] 的含义,这个操作应该就不难理解。

3.用 2 的方法求 1 的 f 数组 
如果我们要求 f 数组,也可以用 2 的方法来求。如果 h.back() < num,那么 f[i] 就等于 push_back(num) 之后的 h.size()。如果 h.back() >= num,设二分查找找到的 iterator 为 it,那么 f[i] = it - h.begin() + 1。

这道题用n^2的做法爆了,得用二分:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int n;
int f[MAXN],maxf = -1;
vector<int> h;
h::iterator it;
int main()
{
cin >> n;
for(int i = 0;i < n;i++)
{
int num;
scanf("%d",&num);
if(h.empty())
{
h.push_back(num);
f[i] = 1;
}
else{
if(num > h.back())
{
h.push_back(num);
f[i] = h.size();
}
else{
int len = h.size();
it = lowerbound(h,h + len,num);
f[i] = it - h.begin() + 1;
}
}
maxf = max(maxf,f[i]);
}
printf("%d\n",maxf);
for(int i = 0;i < n;i++)
{
printf("%d ",f[i]);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值