一、
描述窗口位置 | 最小值 | 最大值 |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
8 3 1 3 -1 -3 5 3 6 7样例输出
-1 -3 -3 -3 3 3 3 3 5 5 6 7
构造一个单调队列并进行维护。以求最小值为例,构造一个队列存储元素的下标,每有一个新的元素,如果队列为空直接插入,若非空,则从队尾开始比较将大于插入元素的都清除,然后插入新元素作为备选。(新元素的下标比旧元素靠后,所以旧元素中比新元素值大的就失去了作为备用最小值的意义,可以清除掉不管)同时,若队首元素超出范围则清除。求最大值的也类似。
e.g . 拿样例来说,元素存放在arr[]中,构造队列que{}。n为8,k为3.
插入扫过第一个元素,直接把下标放入得到que{0}。第二个元素3>1,放入下标后的到que{0,1}.第三个元素-1<1,将数值1和3的下标清除 ,放入下标后得到que{2},这是输出arr[2].第四个元素-3<-1,得到que{3},输出arr[3],第五个5>-3.得到que{3.4}....
#include
#include
using namespace std;
int arr[1000000];
int que[1000000];
int head = 0, rear = -1;
int empty()
{
return rear < head;
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++) scanf("%d", &arr[i]);
int i = 0;
//最小值
while(i < n){
while(arr[i] <= arr[que[rear]] && rear >= head) rear--; //找到新插入元素的位置,并清除大于该元素的旧元素
que[++rear] = i; //插入新元素的下标
while(!empty() && que[head] < i-k+1) head++; //清除队首超出范围的元素
if(i >= k-1) printf("%d ", arr[que[head]]); //输出队首(最小值)
i++;
}
printf("\n");
i = head = 0;
rear = -1;
while(i < n){
while(arr[i] >= arr[que[rear]] && rear >= head) rear--;
que[++rear] = i;
while(!empty() && que[head] < i-k+1) head++;
if(i >= k-1) printf("%d ", arr[que[head]]);
i++;
}
return 0;
}
二、
描述
农夫John 的N(1 ≤ N ≤ 80,000)只奶牛中,有一些也许正在经历发型糟糕的一天。每只奶牛对自己乱糟糟的发型都有自知之明,农夫John想知道所有奶牛能看到其他奶牛头顶的数量之和。
任意奶牛i身高记为 hi (1 ≤ hi ≤ 1,000,000,000),所有奶牛面向东方(本题示意图的右面)依次站成一条线。因此,奶牛i能够看到在它前面的(奶牛i+1,i+2…)所有身高比它低的奶牛,直到被一头比它高的奶牛挡住
考虑如下的例子:
= = = = - = Cows facing right -> = = = = - = = = = = = = = = 1 2 3 4 5 6
奶牛#1 可以看见奶牛#2, 3, 4的头顶
奶牛#2 无法看到任何奶牛的头顶
奶牛#3可以看见奶牛#4的头顶
奶牛#4无法看到任何奶牛的头顶
奶牛#5可以看见奶牛#6的头顶
奶牛#6无法看到任何奶牛的头顶!
用ci表示奶牛i能够看到头顶的奶牛个数;请计算c1 至cN的和。对于上面这个例子,其和为:3 + 0 + 1 + 0 + 1 + 0 = 5。
输入 第1行:奶牛数N
第2行至N+1行:第i+1行包含一个整数,表示奶牛i的高度
6 10 3 7 4 12 2样例输出
5
这道题目跟上一道类似,可以通过维护一个单调递减队列实现。构造一个单调递减队列存储高度,每次插入一个新元素时,清除比该元素小的元素(因为高度小被当前奶牛挡住了,不用再计算了),该元素作为队尾元素,此时排在该元素前面的都是比他高的都能看见他,所以ans += rear-head;
#include
using namespace std;
int que[80000];
int head = 0, rear = -1;
int main()
{
int n, input;
long long ans = 0;
cin >> n;
while(n--){
cin >> input;
while(rear >= head && input >= que[rear]) rear--; //清除矮的
que[++rear] = input; //插入
ans += rear - head; //统计
}
cout << ans << endl;
return 0;
}