题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意:在序列 { 2, 4, 3, 1 } 中,逆序依次为 (2,1), (4,3), (4,1), (3,1),因此该序列的逆序数为 4,题目给定一个长度为n的数组,每次可以把数组的前m个元素移动到数列的后面,所以共有n种数列,求这n种序列中,逆序数最小的一个

思路:(1)从第一种情况,递推剩下的情况,如果把a[1]放到末尾,则逆序数减少a[1](从0到a[1]-1),逆序数增加n-(a[1]+1)(从a[1]+1到n)

(2)用sum数组标记到目前为止,这个数是否存,用线段树每次查询比它大的数有几个,初始的情况推出来了,剩下的情况和上面所用的方法一样

AC代码1:


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

int a[5010];

int main()
{
int i,j;
int n;
while(scanf("%d",&n) != EOF)
{
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
int sum = 0;
for(i=0; i<n; i++)
{
for(j=i+1; j<n; j++)
{
if(a[i] > a[j])
{
sum++;
}
}
}
int min1 = sum;
for(i=0; i<n; i++)
{
sum = sum - a[i] + n - 1 - a[i];
if(sum < min1)
min1 = sum;
}
printf("%d\n",min1);
}
}

AC代码2:


#inlcude <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

typedef long long ll;
using namespace std;

int a[5010];
int cf[5010];//也可以每次在merge1函数里面每次开一个数组,这样比较省内存
int lol[5010];
int sum;

void merge1(int b,int e)
{
int i = b;
int mid = (b + e) / 2;
int j = mid + 1;
int temp = b;
while(i <= mid && j <= e)
{
if(a[i] <= a[j])
{
cf[temp++] = a[i];
i++;
}
else
{
cf[temp++] = a[j];
j++;
sum += mid - i + 1;//i到mid都比这个数大
}
}
while(i <= mid)
{
cf[temp++] = a[i];
i++;
}
while(j <= e)
{
cf[temp++] = a[j];
j++;
}
for(i=b; i<=e; i++)
{
a[i] = cf[i];
}
}

void merge_sort(int b,int e)
{
if(b < e)
{
int mid = (b + e) / 2;
merge_sort(b,mid);
merge_sort(mid+1,e);
merge1(b,e);
}
}

int main()
{
int i;
int n;
while(scanf("%d",&n) != EOF)
{
sum = 0;
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
lol[i] = a[i];
}
merge_sort(0,n-1);
int min1 = sum;
for(i=0; i<n; i++)
{
sum = sum - lol[i] + n - 1 - lol[i];
if(sum < min1)
min1 = sum;
}
printf("%d\n",min1);
}
}

AC代码3:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>
const int inf = 0x3f3f3f3f;//1061109567
typedef long long LL;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 5010;
int sum[maxn<<2],a[maxn];
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);
}
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;
int ans = 0;
if(L <= m) ans += query(L,R,lson);
if(R > m) ans += query(L,R,rson);
return ans;
}
void updata(int p,int l,int r,int rt)
{
if(l == r)
{
sum[rt]++;
return;
}
int m = (l + r) >> 1;
if(p <= m) updata(p,lson);
if(p > m) updata(p,rson);
pushup(rt);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
build(0,n-1,1);
int sum = 0;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
sum += query(a[i]+1,n-1,0,n-1,1);
updata(a[i],0,n-1,1);
}
int min1 = sum;
for(int i=0; i<n; i++)
{
sum = sum - a[i] + n - 1 - a[i];
if(sum < min1)
min1 = sum;
}
printf("%d\n",min1);
}
return 0;
}