保衛方案
戰爭遊戲的至關重要環節就要到來了,這次的結果將決定王國的生死存亡,小B負責首都的防衛工作。首都位於一個四面環山的盆地中,周圍的n個小山構成一個環,作爲預警措施,小B計劃在每個小山上設置一個觀察哨,日夜不停的瞭望周圍發生的情況。 一旦發生外地入侵事件,山頂上的崗哨將點燃烽煙,若兩個崗哨所在的山峯之間沒有更高的山峯遮擋且兩者之間有相連通路,則崗哨可以觀察到另一個山峯上的烽煙是否點燃。由於小山處於環上,任意兩個小山之間存在兩個不同的連接通路。滿足上述不遮擋的條件下,一座山峯上崗哨點燃的烽煙至少可以通過一條通路被另一端觀察到。對於任意相鄰的崗哨,一端的崗哨一定可以發現一端點燃的烽煙。 小B設計的這種保衛方案的一個重要特性是能夠觀測到對方烽煙的崗哨對的數量,她希望你能夠幫她解決這個問題。原題連接:https://www.nowcoder.com/test/question/e1967ae812ea42e7a3ce57ee1f83b686?pid=5715499&tid=31002562
思路:
利用單調棧,取出每個數左邊和右邊分別離他最大的數,然後計算這樣的對數有多少個,加上兩兩之間的對數,就是總的對數。
首先,找到最大的數,並記錄其下標,作爲壓入棧底的開始,這樣可以保證這個棧在壓入的過程中永不爲空
其次,在壓棧的過程中,如果當前要壓入棧的元素 arr[i] 比棧頂元素小,那麼繼續壓入,
但是如果arr[i]比棧頂元素大,那麼彈出棧頂元素 即爲 top, 那麼 左邊離他最近的數就是彈出後的棧的棧頂,右邊離他最大的就是arr[i], 通過這種方式,就能 找到左右最近最大的值。
以上僅僅考慮不重複元素,即可解決,但是當出現重複元素的時候,需要額外考慮元素之間兩兩的配對,所以我們可以定義一個結構體,來保存這個數存入的次數, 當這個數被彈出的時候,可以直接計算一共有多少對,即 = C_n_2 + n + n ,其中 n 表示這個數的重複次數。
C_n_2 是表示,從這n個數中,取出不重複的對爲 C_n_2,而如果左邊數還在,則還要+ n 個對,因爲 這n個數字分別要和這個最大的數進行配對,所以有n個,而右邊如果也存在比他大的數的話,也是同理。
其他的就是考慮最大的數,因爲最大的數只能自己之間互相配對,爲 C_n_2
代碼:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<stack>
using namespace std;
struct node{
int num;
int count;
node(int num){
this->num = num;
this->count = 1;
}
};
typedef long long ll;
int N;
int arr[1000000+100];
stack<node> stk;
int get_next(int id,int len){
return id>=(len-1)?0:id+1;
}
void scanfArr(){
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d",&arr[i]);
}
}
void printfArr(){
for(int i=0;i<N;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
ll getC_n_2(int n){
return n== 1? 0: (ll)n *(ll)(n-1)/(ll)2;
}
int main(){
scanfArr();
int max_idx = 0;
int max_num = arr[max_idx];
for(int i=0;i<N;i++){
if(arr[i]>max_num){
max_num = arr[i];
max_idx = i;
}
}
int idx = get_next(max_idx,N);
node a = node(arr[max_idx]);
stk.push(a);
ll sum = 0;
while(idx != max_idx){
node temp = stk.top();
if(arr[idx]>temp.num){
stk.pop();
sum += getC_n_2(temp.count);
sum +=temp.count;
if(!stk.empty()) sum+= temp.count;
if (!stk.empty() && arr[idx] == stk.top().num){
stk.top().count++;
}else{
node new_ = node(arr[idx]);
stk.push(new_);
}
}else if(arr[idx]<temp.num){
node new_ = node(arr[idx]);
stk.push(new_);
}else if( arr[idx] == temp.num){
stk.top().count++;
}
idx = get_next(idx,N);
}
while(!stk.empty()){
node temp = stk.top(); stk.pop();
sum+= getC_n_2(temp.count);
if(!stk.empty()){
sum+= temp.count;
node temp_no = stk.top();
if(temp_no.num == max_num){
sum+= temp_no.count>1? temp.count:0;
}else {
sum+= temp.count;
}
}
}
printf("%ld\n",sum);
return 0;
}