火车站的列车调度铁轨的结构如下图所示。
![](http://nos.patest.cn/lp_o9wf01q8p76.jpg)
Figure
两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?
输入格式:
输入第一行给出一个整数N (2 <= N <= 105),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。
输出格式:
在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。
输入样例:9 8 4 2 5 3 9 1 6 7输出样例:
4
题目是问 最少需要多少条铁轨,让能使得列车序号倒着输出。说得有点云里雾里。
首先把样例解释一下,因为他是按照 8 4 2 5 3 9 1 6 7 的顺序进入候车区。然后我们要出车顺序是9~1.那么首先我们要9号车先走,但是9之前有5辆车先进了。那么是要5条铁轨吗?明显不是,因为我们要求出车顺序是从大到小。那么只要每条铁轨上的车队从左到右按 从小到大排列的话就ok。
所以问题就转变为原序列可分为多少个下降的子序列。
这个的求法可以参考我另一个博客,cf上的一道题。
这里就不多赘述。
下面是代码
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
using namespace std;
const int maxn = (int)(1e5) + 10;
const int inf = 0x7fffffff;
typedef long long LL;
typedef unsigned long long ull;
vector<int>ans[maxn];
int num[maxn], last[maxn];
bool vis[maxn];
void init(int n) {
for (int i = 0; i <= n; i++) {
ans[i].clear();
vis[i] = 0;
last[i] = 0;
}
}
int find(int size, int key)
{
int first = 0, middle;
int half, len;
len = size;
while (len > 0) {
half = len >> 1;
middle = first + half;
if (last[middle] >= key) {//因为我存last时是倒序,所以分段方法要反过来
first = middle + 1;
len = len - half - 1;
}
else
len = half;
}
return first;
}
int main() {
int n;
while (scanf("%d", &n) == 1) {
init(n);
for (int i = 0; i < n; i++)
scanf("%d", &num[i]);
reverse(num, num + n);
int cnt = 0;
for (int i = 0; i < n; i++) {
bool flag = false;
if (i == 0) {
ans[cnt].push_back(num[i]);
last[cnt++] = num[i];
continue;
}
int t = find(cnt, num[i]);
if (t == 0) {//num[i]比所有末尾都大
ans[0].push_back(num[i]);
last[0] = num[i];
}
else if (t == cnt) {//num[i]比所有末尾都小
last[cnt] = num[i];
ans[cnt++].push_back(num[i]);
}
else {
last[t] = num[i];
ans[t].push_back(num[i]);
}
}
printf("%d\n", cnt);
}
}