http://acm.fzu.edu.cn/problem.php?pid=2320
显然是切得越多答案越小
那么就从左到右枚举切一刀的位置,维护两个树状数组,左边的数字情况和右边的数字情况。
那么向右挪动一位,就相当于把a[i]从右边换到左边,那么就减去a[i]与右边数字组成逆序对的数量,加上a[i]与左边组成逆序对的数量就行了。
#include<cstdio>
#include<algorithm>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,cnt,tot;ll ans;
int a[maxl],bl[maxl],br[maxl];
char s[maxl];
bool in[maxl];
inline void prework()
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),bl[i]=br[i]=0;
}
inline void add(int b[],int i,int x)
{
while(i<=n)
{
b[i]+=x;
i+=i&-i;
}
}
inline ll sum(int b[],int i)
{
ll ret=0;
while(i)
{
ret+=b[i];
i-=i&-i;
}
return ret;
}
inline void mainwork()
{
ll ansl=0,ansr=0;
for(int i=1;i<=n;i++)
{
ansr+=sum(br,n)-sum(br,a[i]);
add(br,a[i],1);
}
ans=0;
for(int i=1;i<=n-1;i++)
{
ansl+=sum(bl,n)-sum(bl,a[i]);
add(bl,a[i],1);
add(br,a[i],-1);
ansr-=sum(br,a[i]-1);
ans=max(ansl+ansr,ans);
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
while(~scanf("%d",&n))
{
prework();
mainwork();
print();
}
return 0;
}