你相信引力吗?(一道单调栈的题)

这道题我想了很久,没想出来。

首先我们要把这个环,找一个断点,给断成序列。

当然是从最大的点断开是最好的,不会有两个点(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;
 } 

猜你喜欢

转载自blog.csdn.net/Bluelanzhan/article/details/83547872