1. 程式人生 > >你相信引力嗎?(一道單調棧的題)

你相信引力嗎?(一道單調棧的題)

這道題我想了很久,沒想出來。

首先我們要把這個環,找一個斷點,給斷成序列。

當然是從最大的點斷開是最好的,不會有兩個點(i,j),如下圖,藍色一段是不可能使(i,j)危險的,因為i,j 小於最大值。

使i,j成為危險的只有可能i到j中沒有嚴格大於i和j的。

這樣,我們先不考慮第一個點為右端點的情況,正著跑一遍單調棧(單調遞減),

假設i要進棧,如果棧頂小於i ,那麼彈棧,i和棧頂會產生1的貢獻。

如果i == 棧頂,那麼i會和所有與棧頂的值相同的元素都產生1的貢獻。

同時會和棧中大於棧頂的第一個元素產生1的貢獻。

然後i進棧。

棧單調遞減,同時維護相同元素的個數。

然後我們要處理的就是以第一個點作為右端點的滿足條件的點對。(有兩種方法)

第一:

假設左端點為i ,也就是說從i到末尾沒有一個元素嚴格大於i。

倒著for一遍就好。

但是注意,如果遇到次大值就break了。。。。(因為正著單調棧的時候,已經算過最大值和次大值的貢獻了。而對於次大值後面的數,如果它大於所有它後面的數顯然是可以和第一個點組成危險冰錐的)

第二:
如果是以第一個點作為右端點的滿足條件的點對,那麼肯定不能和第一次正著for的時候有重疊=。=

對於冰錐i,它一定是i-n裡最高的,但一定不是1-i裡最高的。

統計這樣的冰錐數就好。

//有兩份程式碼,第一份是我的(單調棧寫的比較醜,有點慢,用了離散化,找以第一個點作為右端點的滿足條件的點對時用的第一種方法),第二份是同學的(找以第一個點作為右端點的滿足條件的點對時用的第二種方法)。

#include<bits/stdc++.h>
using namespace std;
int n, vis[5000005], a[5000005] ,ma, wcma, wma, cma ,b[5000005], zhan[5000005], top, tp,  len[5000005], cnt, sval[5000005], ans;
int main()
{
	scanf("%d",&n);
    for(int i = 1; i <= n; i++)
     {
     	 scanf("%d",&a[i]);
     	 if(a[i] > ma)
     	 {
     	 	ma = a[i];   wma = i;
		  }
	   } 
	for(int i = wma; i <= n; i++)
	{
		b[++cnt] = a[i];    sval[cnt] = a[i];
	}
	for(int i = 1; i < wma;i++)
	{
			b[++cnt] = a[i];   sval[cnt] = a[i];
    }
	sort(sval+1,sval+1+n);
	cma = sval[n-1];
	int m = unique(sval+1,sval+1+n) - sval - 1;
    for(int i = 1; i <= cnt; i++)
    {
    	b[i] = lower_bound(sval+1,sval+1+m,b[i]) - sval; 
	}
	cma = lower_bound(sval+1,sval+1+m,cma) - sval; 
	zhan[++top] = b[1];
	vis[b[1]]++;
	for(int i = 2; i <= cnt; i++)
    {
			while(top && (zhan[top] < b[i]))
			{
				ans ++;
				vis[zhan[top]]--;
				top--;
			}
			if(zhan[top] == b[i] && top)
			{
				ans += vis[zhan[top]];
				if(top - vis[zhan[top]] > 0) ans ++; 
				vis[zhan[top]]++;  zhan[++top] = b[i];
			}
			else
			{
			  if(top)ans++;	zhan[++top] = b[i]; vis[b[i]]++;
			}
	}
	int ha = 0;
	for(int i = n; i >=2; i--)
	{
	   if(b[i] == cma) break;
	   if(b[i] >= ha)
	   {	ans++;   	ha = b[i];}
	}
	cout << ans;
	return 0;
 } 
#include<bits/stdc++.h>
using namespace std;

const int N = 5000005;
int n, a[N] ,ma, wma, b[N], top, cma[N], tp,  len[N], cnt, sval[N], ans, tmp[N], lma[N], rma[N];
struct node {
	int size, val;
	node(int val = 0, int size = 0): size(size), val(val) {}
}zhan[N];

int main()
{
	scanf("%d",&n);
    for(int i = 1; i <= n; i++)
     {
     	 scanf("%d",&a[i]);
     	 if(a[i] > ma)
     	 {
     	 	ma = a[i];
     	 	wma = i;
		  }
	   } 
	for(int i = wma; i <= n; i++)
	{
		b[++cnt] = a[i];
	}
	for(int i = 1; i < wma;i++)
	{
		b[++cnt] = a[i];
    }
    for(int i = 2;i <= n;i ++) {
    	if(b[i] >= tmp[i - 1]) lma[i] = 1, tmp[i] = b[i];
    	else tmp[i] = max(tmp[i], tmp[i - 1]);
    } memset(tmp, 0, sizeof(tmp));
    for(int i = n;i >= 1;i --) {
    	if(b[i] >= tmp[i + 1]) rma[i] = n, tmp[i] = b[i];
    	else tmp[i] = max(tmp[i], tmp[i + 1]);
    }
	zhan[++top] = node(b[1], 1);
	for(int i = 2; i <= n; i++)
    {
		while(zhan[top].val < b[i] && top)
		{
			ans += zhan[top].size;
			top--;
		}	
		if(b[i] == zhan[top].val) {
			ans += zhan[top].size; zhan[top].size ++;
			if(top > 1) ans ++; continue;
		}
		if(top) ans ++;
		zhan[++top] = node(b[i], 1);
	}
	int tp = 0;
	for(int i = 2;i <= n;i ++) if(lma[i] != 1 && rma[i] == n) ans ++;
	cout << ans;
	return 0;
 }