Description
宅邸迅速的燃烧着,必须带贝蒂走出禁书库!凭着感觉,又一次直接找到禁书库的门。
“你,是那个人嘛?”400年了,当初圣域建立结界时没有进入圣域,被伤了心的人工精灵贝蒂,与强欲魔女签订契约,守护宅邸的禁书库,直至“那个人”的到来,那个人会解开贝蒂的心结。
“我不是那个什么人,但我会成为你唯一的人。我会给你幸福!”
精灵与人签订契约,从此相依为命。这便是,永恒的契约。
宅邸里,罗兹瓦尔的房间图书柜后,有一条链接宅邸和圣域的秘密通道,其中有一个神奇的大回环,由 n
n
块石头组成。
第i块石头有一个高度 ai
a
i
,两块不同的石头i,j能够互相看到,则它们在环上的两条路径中有至少一条路径上除了两个端点(即 i,j
i
,
j
)路径上石头高度都不大于min(ai,aj)
m
i
n
(
a
i
,
a
j
)
。
被罗兹瓦尔雇佣的猎肠者躲在这秘密的通道中,为了能够更好的观察通道中的情况,她想知道有多少对石头能够互相看到。
Input
第一行一个正整数 T
T
,表示数据组数。
接下来 T
T
组数据,每组数据第一行读入正整数 n
n
,接下来一行按顺时针顺序读入序列 a
a
表示石块的高度。
Output
T T 行表示每组数据的答案。
Sample Input
1
5
1 2 4 5 3
Sample Output
7
Data Constraint
40%,n≤200
40
%
,
n
≤
200
60%,n≤2000
60
%
,
n
≤
2000
70%,n≤100000
70
%
,
n
≤
100000
80%,n≤1000000,1≤ai≤1000000
80
%
,
n
≤
1000000
,
1
≤
a
i
≤
1000000
100%,n≤1000000,T≤5,1≤ai≤1000000000
100
%
,
n
≤
1000000
,
T
≤
5
,
1
≤
a
i
≤
1000000000
solution
首先对于像这种对于环的题目一般首先会有这样的思路:
①将这段序列复制一段
②选一个作“起点”,该起点的作用就是可以断绝前后关系。
比如这道题,我们就选最大的 ai
a
i
作起点,若存在多个最大点则任选一个,不影响。
接下来就谈谈做法吧。
我们设 a1
a
1
为最大值,那么该序列就变为 a1,a2,a3,...an
a
1
,
a
2
,
a
3
,
.
.
.
a
n
,另外注意在最后再加一个 an+1=a1
a
n
+
1
=
a
1
,表示首尾相接。
且能互相看见的对数。
由 ai<aj
a
i
<
a
j
易得 ∀a[i+1..j−1]≤ai
∀
a
[
i
+
1..
j
−
1
]
≤
a
i
,所以能与 ai
a
i
匹配的 aj
a
j
是第一个比 ai
a
i
大的数,即存在唯一性!
我们设这个 aj
a
j
为 next[i]
n
e
x
t
[
i
]
。
所以除了 ai=a1
a
i
=
a
1
的 ai
a
i
外(即为该数亦为最大值),其实全部的 ai
a
i
都有与之对应的 next[i]
n
e
x
t
[
i
]
,可以线性统计答案,具体来讲就是单调栈维护不上升序列。
但是为了保证不算重,所以我们要将那些 aj=an+1
a
j
=
a
n
+
1
(即 a1
a
1
) 的数打上 tag
t
a
g
,然后我们倒过来再做一遍统计答案,遇到带有 tag
t
a
g
且 next[i]=a1
n
e
x
t
[
i
]
=
a
1
的就不必算入答案内。
的情况呢
显然我们也可以在单调栈中统计连续的数出现的次数。
神马?还不懂?如果出现次数是 z
z
,那不就有z∗(z−1)/2
z
∗
(
z
−
1
)
/
2
吗?
code
#include<cstdio>
#define maxn 1000005
using namespace std;
int a[2*maxn],dt[2*maxn],p[2*maxn];
long long ans,z,d;
int st,t,n,i,j,ma,t2;
int main(){
freopen("forever.in","r",stdin);
freopen("forever.out","w",stdout);
scanf("%d",&t);
for (int t2=1;t2<=t;t2++){
scanf("%d",&n);
ans=0;ma=0;
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
if (a[i]>ma){
st=i;
ma=a[i];
}
}
d=1;dt[d]=st;
for (int i=st+1;i<=st+n;i++){
p[i]=0;
if (a[i]>a[i-1])
while ((d>0)&&(a[i]>a[dt[d]]) ){
ans++;
if (i==st+n) p[dt[d]]=1;
if (a[dt[d]]==a[dt[d+1]]) z++; else{
ans+=z*(z+1)/2;
z=0;
}
d--;
}
ans+=z*(z+1)/2;z=0;
dt[++d]=i;dt[d+1]=0;
}
ans+=(d-1)*(d-2)/2;
d=1;dt[d]=st+n;
for (int i=st+n-1;i>=st;i--){
if (a[i]>a[i+1]) while ((d>0)&&(a[i]>a[dt[d]])){
if ((i!=st) || ((i==st)&&(!p[dt[d]])))ans++;
d--;
}
dt[++d]=i;dt[d+1]=0;
}
printf("%lld\n",ans);
}
fclose(stdin);
fclose(stdout);
}