CSU - 2147 疯狂的企鹅
Description
在鹅厂工作的DJ开始训练起了鹅厂的企鹅们,现在DJ教小企鹅玩一个疯狂的游戏(危险游戏,小朋友请勿模仿)。
现在有一排小企鹅,从左到右编号为1….N,每个小企鹅有一个数字,每天早上,如果一个小企鹅发现他右边的小企鹅的数字比他的小,他就会消灭这个小企鹅。问到了第几天才会没有小企鹅可以被消灭,你需要输出天数-1的值
注:所有小企鹅的数字是1…N的排列
Input
每组数据输入格式如下:
第一行一个整数N (N<=10^6)
第二行N个整数,表示1…N号小企鹅的数字
Output
每组数据一行,每行一个整数表示输出天数-1的值
Sample Input
4
4 2 1 3
Sample Output
2
Hint
对于第一组数据:
DAY1:6 2 3 4 5
DAY2:6 3 4 5
DAY3:6 4 5
DAY4:6 5
DAY5:6
对于第二组数据:
DAY1:6 3 5
DAY2:6 5
DAY3:6
对于第三组数据:
DAY1:6
Source
Author
Wells
直接看代码吧
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 1e6 + 5;
int n;
int a[maxn],b[maxn];//数组a保存小企鹅序列,数组b保存其下标
int main(){
while(~scanf("%d",&n)){
for(int i = 1 ; i <= n ; ++i){
scanf("%d",a+i);
}
int x = a[1];
b[0] = b[1] = 1;
// b数组,从数组a的第一个数开始,遇到比这个数大的数,就把该数的下标存到b中
// 并更新与后面的数比较的那个数
// 这个就能实现在数组a中一段一段的查找更新
// b[0]保存数组b存的下标个数
for(int i = 2 ; i <= n ; ++i){
if(x < a[i]){
x = a[i];
b[++b[0]] = i;
}
}
b[++b[0]] = n+1;
// 因为我们也要查找a数组中最后一个x后面的序列,所以b数组保存的最后一个下标就是n+1
// 因此,到此时数组b是存了数组a的第一个数的下标,中间存出现比前面的数(不是指前一个数)
// 大的数的下标,最后一个数存a数组的最后一个数的下标
int ans = 0;
//从b数组的第一个保存的下标开始,往后面一段一段的搜索,所以应该是搜索(b[0]-1)次
for(int i = 1 ; i < b[0] ; ++i){
//于是,x是a[b[i]] k 保存此段的搜索结果
x = a[b[i]];
int k = 0;
//搜素该段序列,下标从b[i]+1到b[i+1]结束
for(int j = b[i] + 1 ; j < b[i+1] ; ++j ){
// 如果下面的两个if都没有进入,就
// 说明其实在数组b保存的这段序列中,满足单调递减哦哦哦~~~~~
k++;
ans = max(ans , k);
if(x < a[j]){
// what?觉得这里没有意义啊,根本进不来
// 是进得来的,只是在没有进入下一个if之前不会进入这个if,
// 因为下一个if中x更新啦
// ^__^**^__^嘻嘻嘻
// 不过,虽然可以进来,但是这段代码意义是什么呢,我注释掉了提交也AC
// 所以还是觉得这个代码没有意义嚯哈哈
ans = max(ans,k);
x = a[j];
k = 0;
continue;
}
// 前面存下来的a[b[i]]企鹅不用去吃这段序列的所有企鹅
// 因为即将出现该段序列内也有企鹅可以内部吃企鹅啦啦啦啦
// 此时更新x和k,序列的规模也可以理解为变小了,哈哈哈
if(a[j] > a[j+1]){
x = a[j];
k = 0;
}
}
}
printf("%d\n",ans);
}
return 0;
}
/**********************************************************************
Problem: 2147
User: MM390117
Language: C++
Result: AC
Time:300 ms
Memory:9836 kb
**********************************************************************/