https://www.luogu.org/problemnew/show/P4372
题意:如果数组A中A[...i]的最大值<=A[i+1…]的最小值,则称i和i+1位置之间产生了一个分隔点,然后对分隔点左右递归求解,一个区间只有一个元素就返回,最后求冒泡排序变量work_counter的值,衡量冒泡排序工作量。
思路:
与这两道题是一路的:https://blog.csdn.net/Wen_Yongqi/article/details/87886315
先把数组元素离散化,化为1~n,下面直接说的是1~n。
定义点i:i位置与i+1位置之间的分隔点,
定义t[i]:点i出现的时间,即1~i元素全部到达1~i位置的时间,即最右的本应在分隔点i左边的元素位置maxpos到点i位置的距离。如果本来1~i已经全部在位置1~i里面了,那么t[i]=1,因为冒泡排序至少要扫一遍。
对于任意元素i,i对答案ans产生贡献直到i>=左边最大值并且<=右边最小值,即i左右都产生了分隔点,即点i-1和点i都是分隔点。
所以答案就是Σmax{t[i],t[i-1]},i∈[1,n]。
为什么要取max呢?因为两边必须都是分隔点才行,比如3142,t[2]=2,t[3]=1,位置3要想作为分隔点,必须满足1~2在1~2并且4在4。或者这个例子12543,t[2]=1,t[3]=2,这个3也必须归位。
为什么只考虑1~i从右边到达左边而不是考虑1~i中>i的出去呢?因为1~i大于i的出去未必<=i的进来,而<=i的进来必定>i的出去。
#include<bits/stdc++.h>
using namespace std;
#define maxn 100000+100
#define lowbit(x) (x&-x)
int n,a[maxn],r[maxn],t[maxn];
long long ans;
bool cmp(int x,int y)
{
if(a[x]!=a[y])return a[x]<a[y];
return x<y;
}
int main()
{
// freopen("input.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],r[i]=i;
sort(r+1,r+1+n,cmp);
for(int i=1;i<=n;i++)a[r[i]]=i;
int maxpos=0;
for(int i=1;i<=n;i++)
{
maxpos=max(maxpos,r[i]);
t[i]=max(1,maxpos-i);
}
for(int i=1;i<=n;i++)ans+=max(t[i-1],t[i]);
cout<<ans<<endl;
return 0;
}