?
题意
? ? 给出一列n个数字,每一个数字都和其他数字不同,现在每次都把第一个数挪到最后面,求这个过程中这个数列逆序数对最少有多少对。
?
思路
? ? ? 先用线段树求出初始的数列逆序对数,再用第一个数列推出第二个,第三个直到第n个,输出最小的那个
? ? ? 这里关键是线段树在lonn的时间复杂度内求出当前数列逆序数对的方法,每次插入一个数,num[i] ,都查询一遍在num[i]+1---n中存在多少个已经插入的点。
?
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int nMax = 6000;
struct{
int l,r,val;
}node[nMax*4];
int num[nMax];
void build(int l, int r, int u){ //建树
node[u].val = 0;
node[u].l=l;
node[u].r=r;
if(l == r){
return;
}
int m = (l+r)/2;
build(l , m ,u*2);
build(m+1 , r, u*2 + 1);
}
void update(int p,int u){ //更新
int l = node[u].l;
int r = node[u].r;
if(l == r){
num[u]++;
}else{
int m = (l + r)>>1 ;
if( p <= m ){
update(p , u*2) ;
}else{
update (p ,u * 2 + 1) ;
}
num[u] = ( num[u*2] + num[u*2+1]) ;
}
}
int query(int le ,int ri ,int u){ //查询
int l = node[u].l;
int r = node[u].r;
if(le <= l && r <= ri ){
return num[u];
}
int m = ( l + r ) >> 1 , res = 0 ;
if(ri >= m + 1 ){
res += query(le , ri ,u * 2 + 1 );
}
if( le <= m ){
res += query(le , ri , u * 2 );
}
return res;
}
int ipt[nMax];
int main(){
int n , i, j ,a ,b ,c , sum ;
while(scanf("%d",&n)!=EOF){
sum = 0;
memset(num , 0, sizeof(num));
build(0 , n-1, 1);
for(i = 0; i < n ; i++){
scanf("%d",&ipt[i]);
update( ipt[i] ,1);
sum += query(ipt[i] + 1 , n-1 , 1);
}
int ans = sum ;
// cout<<ans<<endl;
for(i = 0 ;i < n ; i++ ){
sum = sum - 2 * ipt[i] + n -1 ;
ans = min(ans , sum);
}
printf("%d\n",ans);
}
return 0;
}
?
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int nMax = 6000;
struct{
int l,r,val;
}node[nMax*4];
int num[nMax];
void build(int l, int r, int u){ //建树
node[u].val = 0;
node[u].l=l;
node[u].r=r;
if(l == r){
return;
}
int m = (l+r)/2;
build(l , m ,u*2);
build(m+1 , r, u*2 + 1);
}
void update(int p,int u){ //更新
int l = node[u].l;
int r = node[u].r;
if(l == r){
num[u]++;
}else{
int m = (l + r)>>1 ;
if( p <= m ){
update(p , u*2) ;
}else{
update (p ,u * 2 + 1) ;
}
num[u] = ( num[u*2] + num[u*2+1]) ;
}
}
int query(int left, int right, int u){ // 查询。
if(node[u].l == left && node[u].r == right)
return num[u];
if(right <= node[2*u].r)
return query(left, right, 2*u);
if(left >= node[2*u+1].l)
return query(left, right, 2*u+1);
int a = query(left, (node[u].l+node[u].r)/2, 2*u);
int b = query((node[u].l+node[u].r)/2+1, right, 2*u+1);
return a + b;
}
int ipt[nMax];
int main(){
int n , i, j ,a ,b ,c , sum ;
while(scanf("%d",&n)!=EOF){
sum = 0;
memset(num , 0, sizeof(num));
build(0 , n-1, 1);
for(i = 0; i < n ; i++){
scanf("%d",&ipt[i]);
sum += query(ipt[i], n-1 , 1);
update( ipt[i] ,1);
}
int ans = sum ;
// cout<<ans<<endl;
for(i = 0 ;i < n ; i++ ){
sum = sum - 2 * ipt[i] + n -1 ;
ans = min(ans , sum);
}
printf("%d\n",ans);
}
return 0;
}
?
原文:http://bbezxcy.iteye.com/blog/2159899