HDU - 1394
while
(
scanf
(
"%d"
,&
n
)!=
EOF
)
{
t
=
0
,
ans
=
99999999
;
for
(
int
i
=
1
;
i
<=
n
;
i
++)
scanf
(
"%d"
,&
map
[
i
]);
for
(
int
i
=
1
;
i
<=
n
;
i
++)
for
(
int
j
=
i
+
1
;
j
<=
n
;
j
++)
if
(
map
[
i
]>
map
[
j
])
t
++;
ans
=
t
;
for
(
int
i
=
1
;
i
<=
n
;
i
++)
{
t
=
t
-
map
[
i
]+
n
-
map
[
i
]-
1
;
ans
=
min
(
t
,
ans
);
}
printf
(
"%d\n"
,
ans
);
}
return
0
;
题目大意:N 个数 , 从 0 至 N-1 。给定出事序列,标记为状态 1。
一种操作:将首元素放置到最后。
一共进行 N-1 次操作,每次操作形成一种新的状态。加上初始状态一共 N 个状态。
求 N 种状态中逆序数最小的一组的 逆序数。
(1)暴力过:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define M 5010
using namespace
std
;
int
map
[
M
];
int
n
,
ans
,
t
;
int
main
()
{
//freopen("in.txt","r",stdin);
}
(2)线段树:
#include <iostream>
#include <cstdio>
#include<cstring>
#define min(x,y) (x<y?x:y)
#define Max 5005
#define Inf 0x7fffffff
using namespace std;
int sum[Max<<2];
void build(int l,int r,int id)
{sum[id] = 0;
if(l==r) return;
int mid=(l+r)/2;
build(l,mid,id*2);
build(mid+1,r,id*2+1);
}
void update(int x,int l,int r,int id)
{
if(x==l&&l==r) { sum[id]++; return; }
int mid=(l+r)/2;
if(x<=mid)
update(x,l,mid,id*2);
else
update(x,mid+1,r,id*2+1);
sum[id]++;
return;
}
int query(int x,int l,int r,int id)
{ if(l==r) return 0;
int mid = (l+r)/2;
if(x<=mid) { return query(x,l,mid,id*2)+sum[id*2+1]; }
else { return query(x,mid+1,r,id*2+1); }
return 0;
}
int x[Max];
int n;
int main()
{ //freopen("in.txt","r",stdin);
int i,j;
while(scanf("%d",&n)!=EOF)
{ build(1,n,1); int sums=0;
for(i=0;i<n;i++)
{ scanf("%d",&x[i]);
sums+=query(x[i],0,n-1,1);
update(x[i],0,n-1,1);
}
int min=sums;
for(i=0;i<n-1;i++)
{ min+=n-x[i]*2-1;
sums=min(min,sums);
}
printf("%d\n",sums);
}
return 0;
}