题目大意:
给定一个int型序列,长度为n(n ≤ 5,000),序列就是数字0 ~ n - 1的一个排列,将序列首元素放到末尾就可以得到一个新的序列,重复这样操作n此就又回到了原序列,求这n个序列中逆序数最小的序列,并输出其最小逆序数的个数,测例数为t。
线段树:
注释代码:
/*
* Problem ID : HDU 1394 Minimum Inversion Number
* Author : Lirx.t.Una
* Language : C
* Run Time : 31 ms
* Run Memory : 228 KB
*/
#include <memory.h>
#include <stdio.h>
//序列最大长度
#define MAXN 5000
#define LFT(T) ( (T) << 1 )
#define RHT(T) ( LFT(T) | 1 )
short a[MAXN];//存放
//根结点区间为0 ~ n
//按顺序查询一个数的逆序数时,如果一个数为a
//则查询区间a + 1 ~ n之间数的个数就行了
//注意末尾要多留一个n,因为查n - 1时,查询区间的左端点为n
//左端点不能大于右端点,所以右端点是n而不是n - 1
short seg[MAXN << 1];//线段树
int
query( int tree, int ql, int qr, int lft, int rht ) {
int mid;
if ( lft == ql && qr == rht ) return seg[tree];
mid = ( lft + rht ) >> 1;
if ( qr <= mid ) return query( LFT(tree), ql, qr, lft, mid );
else if ( ql > mid ) return query( RHT(tree), ql, qr, mid + 1, rht );
else return query( LFT(tree), ql, mid, lft, mid ) +
query( RHT(tree), mid + 1, qr, mid + 1, rht );
}
void
insert( int tree, int v, int lft, int rht ) {
int mid;
seg[tree]++;
if ( lft != rht ) {
mid = ( lft + rht ) >> 1;
if ( v <= mid ) insert( LFT(tree), v, lft, mid );
else insert( RHT(tree), v, mid + 1, rht );
}
}
int
min( int a, int b ) {
return a < b ? a : b;
}
int
main() {
int n;//序列长度
int i;
int inv;//逆序数
int ans;//最后的答案
while ( ~scanf("%d", &n) ) {
inv = 0;
memset(seg, 0, sizeof(seg));
for ( i = 0; i < n; i++ ) {
scanf("%d", a + i);
inv += query( 1, a[i] + 1, n, 0, n );
insert( 1, a[i], 0, n );
}
ans = inv;
for ( i = 0; i < n - 1; i++ )
//如果首元素为a[i],则放到末尾后逆序数的变化量为
//n - 1 - 2a[i]
ans = min( ans, inv += n - 1 - ( a[i] << 1 ) );
printf("%d\n", ans);
}
return 0;
}
无注释代码:
#include <memory.h>
#include <stdio.h>
#define MAXN 5000
#define LFT(T) ( (T) << 1 )
#define RHT(T) ( LFT(T) | 1 )
short a[MAXN];
short seg[MAXN << 1];
int
query( int tree, int ql, int qr, int lft, int rht ) {
int mid;
if ( lft == ql && qr == rht ) return seg[tree];
mid = ( lft + rht ) >> 1;
if ( qr <= mid ) return query( LFT(tree), ql, qr, lft, mid );
else if ( ql > mid ) return query( RHT(tree), ql, qr, mid + 1, rht );
else return query( LFT(tree), ql, mid, lft, mid ) +
query( RHT(tree), mid + 1, qr, mid + 1, rht );
}
void
insert( int tree, int v, int lft, int rht ) {
int mid;
seg[tree]++;
if ( lft != rht ) {
mid = ( lft + rht ) >> 1;
if ( v <= mid ) insert( LFT(tree), v, lft, mid );
else insert( RHT(tree), v, mid + 1, rht );
}
}
int
min( int a, int b ) {
return a < b ? a : b;
}
int
main() {
int n;
int i;
int inv;
int ans;
while ( ~scanf("%d", &n) ) {
inv = 0;
memset(seg, 0, sizeof(seg));
for ( i = 0; i < n; i++ ) {
scanf("%d", a + i);
inv += query( 1, a[i] + 1, n, 0, n );
insert( 1, a[i], 0, n );
}
ans = inv;
for ( i = 0; i < n - 1; i++ )
ans = min( ans, inv += n - 1 - ( a[i] << 1 ) );
printf("%d\n", ans);
}
return 0;
}
树状数组:
注释代码:
/*
* Problem ID : HDU 1394 Minimum Inversion Number
* Author : Lirx.t.Una
* Language : C
* Run Time : 31 ms
* Run Memory : 228 KB
*/
#include <memory.h>
#include <stdio.h>
#define MAXN 5001
short a[MAXN];
//树状数组
//c[i]表示数字1 ~ i区间中数字的个数
short c[MAXN];
short lowbit[MAXN];
int n;//序列长度
void
insert(int x) {
while ( x <= n ) {
c[x]++;
x += lowbit[x];
}
}
int
query(int x) {
int sum;
sum = 0;
while ( x > 0 ) {
sum += c[x];
x -= lowbit[x];
}
return sum;
}
int
min( int a, int b ) {
return a < b ? a : b;
}
int
main() {
int inv;
int ans;
int i;
for ( i = 1; i < MAXN; i++ ) lowbit[i] = i & -i;//打表
while ( ~scanf("%d", &n) ) {
inv = 0;
memset(c, 0, sizeof(c));
for ( i = 1; i <= n; i++ ) {
scanf("%d", a + i);
a[i]++;//树状数组下标从1开始
insert(a[i]);
//由于是最后插入a[i]的,插入a[i]后总共有i个数
//而1 ~ a[i]的数有query(a[i])个,因此在a[i]之前大于a[i]的数就有
//i - query(a[i])个,a[i]现在在序列的末尾处!!!
inv += i - query(a[i]);
}
ans = inv;
for ( i = 1; i < n; i++ )//由于下标从1开始算,因此表达式有一点变化
//a[i]变成了a[i] - 1
ans = min( ans, inv += n - 1 - ( ( a[i] - 1 ) << 1 ) );
printf("%d\n", ans);
}
return 0;
}
无注释代码:
#include <memory.h>
#include <stdio.h>
#define MAXN 5001
short a[MAXN];
short c[MAXN];
short lowbit[MAXN];
int n;
void
insert(int x) {
while ( x <= n ) {
c[x]++;
x += lowbit[x];
}
}
int
query(int x) {
int sum;
sum = 0;
while ( x > 0 ) {
sum += c[x];
x -= lowbit[x];
}
return sum;
}
int
min( int a, int b ) {
return a < b ? a : b;
}
int
main() {
int inv;
int ans;
int i;
for ( i = 1; i < MAXN; i++ ) lowbit[i] = i & -i;
while ( ~scanf("%d", &n) ) {
inv = 0;
memset(c, 0, sizeof(c));
for ( i = 1; i <= n; i++ ) {
scanf("%d", a + i);
a[i]++;
insert(a[i]);
inv += i - query(a[i]);
}
ans = inv;
for ( i = 1; i < n; i++ )
ans = min( ans, inv += n - 1 - ( ( a[i] - 1 ) << 1 ) );
printf("%d\n", ans);
}
return 0;
}
单词解释:
inversion:n, 倒置,反转