题意:
解法:
冒泡排序的交换次数就是逆序对数量.
先计算出逆序对.
发现n只有5e3,考虑枚举两个位置i,j,交换a[i],a[j]会减少多少逆序对.
交换i,j,逆序对数量会减少:
+[i+1,j-1]中>a[j]的数的数量
-[i+1,j-1]中>a[i]的数的数量
+[i+1,j-1]中<a[i]的数的数量
-[i+1,j-1]中<a[j]的数的数量
[l,r]中<x或>x的数量可以O(n^2)dp预处理:
令mi[i][j]表示[1,i]中<j的数的数量,
令ma[i][j]表示[1,i]中>j的数的数量.
code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxm=5e3+5;
int ma[maxm][maxm];//ma[i][j]表示[1,i]中>j的数的个数
int mi[maxm][maxm];//mi[i][j]表示[1,i]中<j的数的个数
int a[maxm];
int n;
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<n;j++){
ma[i][j]=ma[i-1][j];
mi[i][j]=mi[i-1][j];
}
for(int j=0;j<a[i];j++){
ma[i][j]++;
}
for(int j=a[i]+1;j<n;j++){
mi[i][j]++;
}
}
ll tot=0;//序列逆序对数量
for(int i=1;i<=n;i++){
tot+=ma[i-1][a[i]];
}
int mx=0,cnt=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int temp=0;//交换a[i],a[j]可以消去的逆序对数量.
temp+=ma[j-1][a[j]]-ma[i][a[j]];//[i+1,j-1]中>a[j]的数量
temp-=ma[j-1][a[i]]-ma[i][a[i]];//[i+1,j-1]中>a[i]的数量
temp+=mi[j-1][a[i]]-mi[i][a[i]];//[i+1,j-1]中<a[i]的数量
temp-=mi[j-1][a[j]]-mi[i][a[j]];//[i+1,j-1]中<a[j]的数量
if(a[i]>a[j])temp++;
else temp--;
if(temp>mx){
mx=temp;
cnt=1;
}else if(temp==mx){
cnt++;
}
}
}
cout<<tot-mx<<' '<<cnt<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}