题意
一个长度为
的环
,如果环上有一对数
,当连接
的两对弧中任意一对上不存在比
大的数,则称
可以互相看见,问有多少对数可以互相看见。
思路
首先,与环有关的问题,最基本的思路就是段环成链。因为连接 的圆弧,一定不必穿过环上的最大值,所以可以去掉环上最大值并把环拆成链,最后重新算一遍最高点的贡献即可。不难发现,将 作为较低点,它能连结的点有左边第一个比它大的点和右边第一个比它大的点,于是想到单调栈。但是这样有一个问题,如果单调栈中出现了相同元素,那么点 还能连接到所有与 大小相同的点。所以还要特殊处理这一类点。单调栈进行的过程中始终保持序列的递减,那只用用 替换栈内元素时,维护一个 数组如果遇到相同元素,则通过累加得到与 相同的元素个数即可。准确的说,是 向左边拓展,在遇到比它大的点时停下,中途遇到与 相等的元素的个数(当然,除了将所有数的 值加起来,也可以加上所有的 ,其中 为一个满足上述要求,值相等的点集中点的个数)。
代码
由于这题有些卡语言,所以用 语言交了
#include<stdio.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 1000003
typedef long long LL;
int mark[N];
int a[N],t[N],s[N],n;
int stk[N],top;
int p,mx=-1,h;
LL ans;
int main()
{
scanf("%d",&n);
FOR(i,1,n)scanf("%d",&t[i]);
FOR(i,1,n)if(t[i]>mx)mx=t[p=i];
FOR(i,1,n-p)a[i]=t[i+p];
FOR(i,n-p+1,n-1)a[i]=t[i-n+p];
n--;
a[0]=2e9,stk[top=0]=0;
FOR(i,1,n)
{
while(a[i]>=a[stk[top]])
{
if(a[i]==a[stk[top]])s[i]=s[stk[top]]+1;
top--;
}
if(top)ans++;
stk[++top]=i;
}
a[n+1]=2e9,stk[top=0]=n+1;
DOR(i,n,1)
{
while(a[i]>=a[stk[top]])top--;
if(top)ans++;
stk[++top]=i;
}
FOR(i,1,n)ans+=s[i];
h=-1;
FOR(i,1,n)
{
if(a[i]>=h)
{
h=a[i];
if(!mark[i])
{
mark[i]=1;
ans++;
}
}
}
h=-1;
DOR(i,n,1)
{
if(a[i]>=h)
{
h=a[i];
if(!mark[i])
{
mark[i]=1;
ans++;
}
}
}
printf("%lld\n",ans);
return 0;
}