刷题杂记之Bindian Signalizing

题目传送门

首先考虑如何处理这个环
可以先找出最大的数,然后最大的数放在第一位,按顺序依次下派,最后再加上这个最大数,那么就不需要处理冗杂的计算了,直接就可以线性计算
思考如何在这个链上处理
对于一个点i,设它的左边的第一个比i大点为 l e f t i left_i lefti,右边第一个比他大的点为 r i g h t i right_i righti,那么有i的区间就是 l e f t i left_i lefti~ r i g h t i right_i righti(如果在这个区间的左边或者右边还有,那么a[i]一定小于a[ l e f t i left_i lefti]和a[ r i g h t i right_i righti],就不符合了)
有一个问题:如何计算这里面的东西,就比如样例

531245

假如对于4这个点,左边的最大是5,右边的最大也是5,坐标分别是0,5,但是包含4的这个点的区间有4个(4-5,3-4,2-4,1-4)
还有在处理完这个区间的时候,在处理1的时候也是包含的,所以在最后的答案还要/2,问题是这个答案还不好求出
那么想一下如何这一个区间的数的性质,这个区间的除了左端点和右端点,其他的数都比i小,那么在处理这些小的数的时候(设为j,即j= Σ i = l e f t i r i g h t i \Sigma_{i=left_i}^{right_i} Σi=leftirighti,显然 l e f t j left_j leftj r i g h t j right_j rightj都不会分别小于和大于 l e f t i left_i lefti r i g h t i right_i righti),如果 l e f t j left_j leftj r i g h t i right_i righti都没有i,那么i和j一定不能互相的转换,那么如果有,就已经可以包含进去了,那么在计算i的时候只需要+2就行了(即 l e f t i left_i lefti r i g h t i right_i righti
但是还有一个特殊的情况——当中间有数等于i的时候,那么对于这些数,只需要用cnt记录一下即可(注意只需要记录右边的,因为左边在遍历的时候已经计算过了)
关于怎么计算这3个东西,不是栈就行了

代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,a[N],b[N],lft[N],rgh[N];
int cnt[N],sta[N],tot;
int main()
{
	scanf("%d",&n);int Max=0,p;
	for(int i=1;i<=n;i++)
	{
	    scanf("%d",&a[i]);
		if(Max<a[i]){
			Max=a[i];p=i;
		}
    }b[0]=Max;long long sum=0;
    for(int i=p+1;i<=n;i++)b[i-p]=a[i];
    for(int i=1;i<=p;i++)b[n-p+i]=a[i];
    for(int i=0;i<=n;i++){
    	while(tot&&b[i]>=b[sta[tot]])tot--;
    	lft[i]=sta[tot];sta[++tot]=i;
	}tot=0;
    for(int i=n;i+1;i--){
    	while(tot&&b[i]>=b[sta[tot]]){
    		if(b[i]==b[sta[tot]])cnt[i]=cnt[sta[tot]]+1;
    		tot--;
		}
    	rgh[i]=sta[tot];sta[++tot]=i;
		if(i!=0)sum+=cnt[i];
	}
	for(int i=0;i<n;i++)
	  if(b[i]<b[0]){//有可能最大的有多个
	    sum+=2;if(lft[i]==0&&rgh[i]==n){
		sum--;}
	  	//这两个其实是一样的,只能算一种 
	  }
	printf("%lld",sum);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值