题目链接:
1027 Larry and Inversions (35分)
思路:
首先计算出原数组逆序数的对数;
然后依次考虑翻转的情况,我们注意到翻转是有规律的:
假设我们已经计算得出了从i翻转到j的逆序数对数,则计算i翻转到j+1的逆序数对数,我们只需知道i到j的数中比第j+1个数小的数的个数,我们记为sm,则比j+1个数大的数的数量自然就是j-i-sm,记为gt,那此次翻转我们新获得的逆序数有sm个,损失的逆序数有gt个;
以上方法需要熟练使用树状数组;
代码:
#include<bits/stdc++.h>
#define lowbit(x) (x&-x)
using namespace std;
const int maxn = 1234;
int n, a[maxn], sum;
void init_(){
vector<int> bit(n + 1);
for(int i = n - 1; i >= 0; i--){
int x = a[i], y = a[i];
while(x) sum += bit[x], x -= lowbit(x);
while(y <= n) ++bit[y], y += lowbit(y);
}
}
void solve(){
for(int i = 0; i < n; i++){
int ans = 0;
vector<int> bit(n + 1);
for(int j = i; j < n; j++){
int x = a[j], y = a[j], sm = 0, gt = 0;
while(x) sm += bit[x], x -= lowbit(x);
while(y <= n) ++bit[y], y += lowbit(y);
gt = j - i - sm;
ans = ans + sm - gt;
if(i || j) putchar(' ');
printf("%d", sum + ans);
}
}
}
int main(){
// freopen("Sakura.txt", "r", stdin);
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", a + i);
init_();
solve();
return 0;
}