hdu 1394 Minimum Inversion Number 请戳
题意:
给长度为 n 的数组 A(0 <= A[i] <= n - 1)。
进行 n - 1 次后移操作,每次将排在第一个的元素移到最后那个元素后面。
没次数组A都有一个逆序数,求最小的逆序数。思路:
线段树计算逆序数,然后所有逆序数都可以递推出来,取最小的即可。
去年作死都没想通为什么线段树能够写求出逆序数,今天看了下。。。居然秒懂。(那么问题来了!我去年干啥去了?)复杂度:
时间复杂度:O(n * log(n))
空间复杂度:O(4 * n)代码:
/* ***********************************************
Author :Ilovezilian
Created Time :2015/9/4 0:57:03
File Name :seg_tree_2.cpp
************************************************ */
#include <bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N = 0,maxn = 5555, mod = 1e9+7;
int sum[maxn<<2];
void pushup(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(int l, int r, int rt)
{
sum[rt] = 0;
if(l == r) return ;
int m = (l + r) >> 1;
build(lson);
build(rson);
}
void update(int p, int l, int r, int rt)
{
if(l == r)
{
sum[rt] ++;
return;
}
int m = (l + r) >> 1;
if(p <= m) update(p, lson);
else update(p, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if(L <= l && r <= R)
{
return sum[rt];
}
int m = (l + r) >> 1, ret = 0;
if(L <= m) ret += query(L, R, lson);
if(R > m) ret += query(L, R, rson);
return ret;
}
int x[maxn];
void solve()
{
int n;
while(~scanf("%d", &n))
{
build(0, n - 1, 1);
int sum = 0;
for(int i = 0; i < n; i ++)
{
scanf("%d", x + i);
sum += query(x[i], n - 1, 0, n - 1, 1); //逆序数就是每次求和。
update(x[i], 0, n - 1, 1);//然后更新
}
int ret = sum;
for(int i = 0; i < n; i ++)
{
sum += n - x[i] - x[i] - 1; //这个递推有意思
ret = min(ret, sum);
}
printf("%d\n", ret);
}
}
int main()
{
//freopen("","r",stdin);
//freopen("","w",stdout);
solve();
return 0;
}