题意:给出一个排列a,定义一个区间[L,R]价值为:该区间中位数*R*L.
n<=1e4 求出奇数区间价值的累加和.
枚举以L开头的区间:先计算[L,n]的中位数:用链表把[L,n]的元素有序的连接起来,记录此时的中位数位置.
关键:每次删除两个数,中位数的位置最多只会向前或者后面偏移一个.
n<=1e4 求出奇数区间价值的累加和.
枚举以L开头的区间:先计算[L,n]的中位数:用链表把[L,n]的元素有序的连接起来,记录此时的中位数位置.
关键:每次删除两个数,中位数的位置最多只会向前或者后面偏移一个.
用L,R记录当前比中位数小和大的个数 根据L,R决定中位数如何移动即可.O(n^2).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+5;
int n,a[N],pre[N],nxt[N],mid,L,R;
bool mk[N];
void del(int x)
{
int P=pre[x],Q=nxt[x];
nxt[P]=Q;
pre[Q]=P;
if(x<mid)
L--;
if(x>mid)
R--;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
ll ans=0;
for(int i=1;i<=n;i++)
{
int st=i,ed=n;
if((n-i+1)%2==0)
ed--;
memset(mk,false,sizeof(mk));
for(int j=i;j<=ed;j++)
mk[a[j]]=true;
int cur=0,cnt=0;
for(int j=1;j<=n;j++)//link in order
{
if(mk[j])
{
nxt[cur]=j;
pre[j]=cur;
cur=j;
cnt++;
if(cnt==(ed-st)/2 +1)
mid=j;
}
}
nxt[cur]=n+1;
pre[n+1]=cur;
L=R=(ed-st)/2;
for(int j=ed;j>=i;j-=2)
{
ans+=(ll)i*j*mid;
del(a[j]);
del(a[j-1]);
if(L==R-2)
{
mid=nxt[mid];
L++;
R--;
}
else if(L==R+2)
{
mid=pre[mid];
L--;
R++;
}
else if(L==R-1)
{
mid=nxt[mid];
R--;
}
else if(L==R+1)
{
mid=pre[mid];
L--;
}
}
}
cout<<ans<<endl;
return 0;
}