无聊都给写了..
其实这道题的关键不是求逆序的方法,因为暴力也可以过。
题意是,给一个长度为n的序列(n<=5000),由0~n-1的数字组成。每次把最左边的数挪到最右边形成一个新的序列。那么一共可以形成n个序列。求这n个序列里面最小的逆序数是多少。
我用数组a[0~n-1]来存原始数据。只需求出原始序列的逆序数sum,然后对于a[i](0<= i <n-1),每挪一个,用sum减去挪之前它右边比它小的数的个数(也就是a[i])、再用sum加上挪之后左边比它大的数的个数(也就是n-a[i]-1),就是挪了a[i]的逆序数了
1.暴力法。
265MS | 212K | 600 B |
Problem : 1394 ( Minimum Inversion Number ) Judge Status : Accepted
RunId : 2732590 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
RunId : 2732590 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define MAX 50001 int n,a[MAX]; int main (){ int i, j, MIN, sum ; while(scanf("%d", &n) != EOF ) { sum = 0 ; for(i = 0; i < n; i ++) { scanf("%d", &a[i]); for(j = 0; j < i; j ++) { if(a[j] > a[i]) sum ++ ; } } MIN = sum ; for(i = 0; i < n-1; i ++){ sum = sum - a[i] + (n - a[i] - 1) ; if(sum < MIN) MIN = sum ; } printf("%d/n", MIN); } return 0 ; }
2.树状数组法。
31MS | 408K | 816 B |
Problem : 1394 ( Minimum Inversion Number ) Judge Status : Accepted
RunId : 2731410 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
RunId : 2731410 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;#define MAX 50001
int c[MAX],n,a[MAX];int getsum(int i){
int res;
for(res=0;i>0;i-=i&(-i)) res+=c[i];
return res;
}
void modify(int i,int m){
for(;i<=MAX;i+=i&(-i)) c[i]+=m;
}
int main (){
int i, j, MIN, sum ;
while(scanf("%d", &n) != EOF )
{
memset(c, 0, sizeof(c)) ;
sum = 0 ;
for(i = 0; i < n; i ++)
{
scanf("%d", &a[i]);
}
for(i = n-1; i >= 0; i --)
{
modify(a[i]+ 1, 1) ;
sum += getsum(a[i]) ;
}
MIN = sum ;
for(i = 0; i < n-1; i ++){
sum = sum - a[i] + (n - a[i] - 1) ;
if(sum < MIN) MIN = sum ;
}
printf("%d/n", MIN);
}
return 0 ;
}
3.线段树法。
46MS | 300K | 1639 B |
Problem : 1394 ( Minimum Inversion Number ) Judge Status : Accepted
RunId : 2733007 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
RunId : 2733007 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int size = 50001 ; struct xds { int lson, rson ; int a, b, info ; }tree[size*3] ; int tot, n, a[size] ; void build(int a, int b) { int now = ++tot ; tree[now].a = a ; tree[now].b = b ; tree[now].info = 0 ; if(a == b) { tree[now].lson = tree[now].rson = 0 ; return ; } int mid = (a + b) >> 1 ; tree[now].lson = tot + 1 ; build(a, mid) ; tree[now].rson = tot + 1 ; build(mid + 1, b) ; } void update(int p, int a) { tree[p].info ++ ; if(tree[p].a == tree[p].b) return ; int mid = (tree[p].a + tree[p].b) >> 1 ; if(a <= mid) update(tree[p].lson, a) ; else update(tree[p].rson, a) ; } int query(int p, int a, int b) { if(tree[p].a == a && tree[p].b == b) { return tree[p].info ; } if(tree[p].a == tree[p].b) return tree[p].info; int mid = (tree[p].a + tree[p].b) >> 1 ; if(b <= mid) return query(tree[p].lson, a, b) ; else if(a > mid) return query(tree[p].rson, a, b) ; else return query(tree[p].lson, a, mid) + query(tree[p].rson, mid + 1, b) ; } int main (){ int i, j, MIN, sum ; while(scanf("%d", &n) != EOF ) { sum = tot = 0 ; build(1, n) ; for(i = 0; i < n; i ++) { scanf("%d", &a[i]); sum += query(1, a[i]+2, n) ; update(1, a[i]+ 1) ; } MIN = sum ; for(i = 0; i < n-1; i ++){ sum = sum - a[i] + (n - a[i] - 1) ; if(sum < MIN) MIN = sum ; } printf("%d/n", MIN); } return 0 ; }
4.归并排序法。
31MS | 240K | 1169 B |
Problem : 1394 ( Minimum Inversion Number ) Judge Status : Accepted
RunId : 2732771 Language : C++ Author : yueashuxia
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 50001
typedef int T ;
T num[MAX],a[MAX],sum,b[MAX];//对num 数组从小到大排序,a 为辅助数组
void mergesort(T left,T mid,T right){
T i=left,j=mid+1,k=0;
while(i<=mid&&j<=right){
if(num[i]<=num[j]) a[k++]=num[i++];
else {
sum+=mid-i+1;//若加此句并初始化sum=0 则排序后sum 为原序列逆序数
a[k++]=num[j++];
}
}
while(i<=mid) a[k++]=num[i++];
while(j<=right) a[k++]=num[j++];
for(i=left,j=0;i<=right;i++) num[i]=a[j++];
}
void merge(T left,T right){ //分治
if(left<right){
merge(left,(left+right)/2);
merge((left+right)/2+1,right);
mergesort(left,(left+right)/2,right);
}
}
int main (){
int n, i, j, MIN, last ;
while(scanf("%d", &n) != EOF )
{
for(i = 0; i < n; i ++)
{
scanf("%d", &num[i]);
b[i] = num[i] ;
}
sum = 0 ;
merge(0, n-1) ;
MIN = sum ;
for(i = 0; i < n-1; i ++){
sum = sum - b[i] + (n - b[i] - 1) ;
if(sum < MIN) MIN = sum ;
}
printf("%d/n", MIN);
}
return 0 ;
}