codeforces 5E Bindian Signalizing

来源:互联网 发布:2017网络时时彩赌博案 编辑:程序博客网 时间:2024/05/18 01:07

Bindian Signalizing

time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Everyone knows that long ago on the territory of present-day Berland there lived Bindian tribes. Their capital was surrounded by n hills, forming a circle. On each hill there was a watchman, who watched the neighbourhood day and night.

In case of any danger the watchman could make a fire on the hill. One watchman could see the signal of another watchman, if on the circle arc connecting the two hills there was no hill higher than any of the two. As for any two hills there are two different circle arcs connecting them, the signal was seen if the above mentioned condition was satisfied on at least one of the arcs. For example, for any two neighbouring watchmen it is true that the signal of one will be seen by the other.

An important characteristics of this watch system was the amount of pairs of watchmen able to see each other’s signals. You are to find this amount by the given heights of the hills.

Input
The first line of the input data contains an integer number n (3 ≤ n ≤ 106), n — the amount of hills around the capital. The second line contains n numbers — heights of the hills in clockwise order. All height numbers are integer and lie between 1 and 109.

Output
Print the required amount of pairs.

Examples
input
5
1 2 4 5 3
output
7

一道类似于dp的题目。。
开始是一个圆形方式,我们只需要找到任意一个最高的点就可以将最高的点设为起点和终点,每一个点都会贡献与他左边最大的点和右边最大的点两对,有相同高度的也会贡献,如果两边都是同一最高点的话贡献只能为1;同为最高点的点只能算作同高度的点。
下面代码

#include<bits/stdc++.h>using namespace std;const int maxn = 1e6 + 10;int num[maxn] , l[maxn] , r[maxn] , cnt[maxn];// r 记录该点右方第一个比该点高的位置(或边界);// l 记录该点左方第一个比该点高的;// cnt记录到右方第一个比该点高的点前和自己同一高度的点的数量;long long ans = 0;int main(){    int n;    cin>>n;    for(int i = 1 ; i <= n ; ++i)        scanf("%d" , num + i);    rotate(num + 1 , max_element(num + 1 , num + n +1) , num + n + 1);    // rotate (beg , mid , end) 以 mid 为中心左右旋转;    // max_element(beg, end) , min_element(beg ,end)找出区间[beg,end)中的最大/小值,返回其位置(迭代器);    num[n + 1] = num[1]; // 转换后最高峰变为num[1],使num[n + 1]为num[1]确保原来左边的递减序列可以看到。    for(int i = n ; i > 0 ; --i)    {        r[i] = i + 1;        while(r[i] <= n && num[r[i]] < num[i])            r[i] = r[r[i]];        if(r[i] <= n && num[i] == num[r[i]])        {            cnt[i] = cnt[r[i]] + 1;            r[i] = r[r[i]];        }    }    for(int i = 1 ; i <= n ; ++i)    {        ans += cnt[i];        //相同高度的叠加        if(num[i] == num[1])            continue;        l[i] = i - 1;        while(l[i] > 1 && num[i] >= num[l[i]])            l[i] = l[l[i]];        ans += 2; //一般向左可构成两对,i - 1 和比num[i]大的第一个数。        if(l[i] == 1 && r[i] == n + 1)          ans--;//没有比其高的点只能和旁边的点成对。    }    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击