日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Minimum Inversion Number HDU - 1394(求一个数字环的逆序对+多种解法)

發布時間:2023/12/4 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Minimum Inversion Number HDU - 1394(求一个数字环的逆序对+多种解法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:

給出n個數(0~n-1,每個數僅出現一次),問它長為n的循環序列中逆序對最少的數量。

多種解法:暴力+樹狀數組+分治+規律推導公式

題目:

The inversion number of a given number sequence a1, a2, …, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

For a given sequence of numbers a1, a2, …, an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, …, an-1, an (where m = 0 - the initial seqence)
a2, a3, …, an, a1 (where m = 1)
a3, a4, …, an, a1, a2 (where m = 2)

an, a1, a2, …, an-1 (where m = n-1)

You are asked to write a program to find the minimum inversion number out of the above sequences.

Input

The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.

Output

For each case, output the minimum inversion number on a single line.

Sample Input

10
1 3 6 9 0 8 5 7 4 2

Sample Output

16

分析:

第一種解法:暴力

1.為了實現環,將數組擴到兩倍a[i+n]=a[i];
2.求出初始串的狀態,即最小逆序對;
3.由(1),直接往后遍歷,每次選取連續的n個數,即效果等同于每次把最后的元素放置最前即可實現環。

AC代碼

/**暴力*/ #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int M=1e4+10; int a[M],b[M]; int n,ans,num,cnt; int main() {while(~scanf("%d",&n)){memset(b,0,sizeof(b));for(int i=0;i<n;i++){scanf("%d",&a[i]);a[i+n]=a[i];}ans=0;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++)if(a[i]>a[j])b[i]++;ans+=b[i];}for(int i=1;i<=n-1;i++){cnt=0;for(int j=i;j<i+n-1;j++){if(a[j]>a[i-1])b[j]++;cnt+=b[j];}if(ans>cnt)ans=cnt;}printf("%d\n",ans);}return 0; }

第二種解法:樹狀數組求逆序數。

1.由題意:n個數(0~n-1,每個數僅出現一次),用樹狀數組來維護[0,n)的區間。
2.每次讀入一個數,將該數存入樹狀數組b[],用樹狀數組來維護[0,n)的區間和。
3.每次先求出區間[ai+1,n)的和,即為ai之前比ai大的數字的個數。
4.由前面,求出初始串的狀態,即最小逆序對
5.如序列a1,a2,a3,a4,a5,它的逆序對數量s=sum(num(ak>ai,k<i));序列變為a2,a3,a4,a5,a1,和上一個序列相比,變化分為兩步。
(1)拿走a1,逆序對減少a1( 整個序列是0~n-1且每個數字僅出現一次)個,
(2)將a1 放入序列尾部;加入序列尾部,逆序對增加n-1-a1個,這樣就可以遞推求解各序列的逆序對個數。

#include<stdio.h>/**樹狀數組求逆序數*/ #include<string.h> #include<algorithm> using namespace std; const int M=5e3+10; int n,ans,num,mi; int a[M],b[M]; int lowbit(int x) {return x&(-x); } int query(int x)///每次先求出區間[ai+1,n)的和,即為ai之前比ai大的數字的個數 {int num=0;x+=1;while(x<=n){num+=b[x];x+=lowbit(x);}return num; } void update(int pos,int val)///用樹狀數組來維護[0,n)的區間和 {while(pos>0){b[pos]+=val;pos-=lowbit(pos);} } int main() {while(~scanf("%d",&n)){ans=0;memset(b,0,sizeof(b));for(int i=0; i<n; i++){scanf("%d",&a[i]);update(a[i]+1,1);///每次讀入一個數,將該數存入樹狀數組b[]ans+=query(a[i]+1);///查詢前面是否有比該數大的數,即為逆序數}mi=ans;for(int i=0; i<n; i++){ans=ans+(n-1)-2*a[i];/**如序列a1,a2,a3,a4,a5,它的逆序對數量s=sum(num(ak>ai,k<i)); 序列變為a2,a3,a4,a5,a1,和上一個序列相比,變化分為兩步,拿走a1和將a1 放入序列尾部;拿走a1,逆序 對減少a1( 整個序列是0~n-1且每個數字僅出現一次)個,加入序列尾部,逆序對增加n-1-a1個,這樣就可 以遞推求解各序列的逆序對個數。*/if(ans<mi)mi=ans;}printf("%d\n",mi);}return 0; }

第三種解法:分治求逆序數

1.用分治求出初始串的狀態,每次把最后的元素放置最前即可實現環。
2.每次移動時:(與前面樹狀樹狀的后面解法一樣)
(1)所有data[i]后面比他小的元素逆序數 -1(0~k-1,k個);
(2)所有data[i]后面比他大的元素逆序數 +1(n-1-k個);
(3)逆序數改變總數是 n - 2*k - 1(k = data[i]);
枚舉不同的首元素,輸出最小的逆序數即可。

#include <stdio.h> #include <stdlib.h> const int M=5e3+10; int a[M]; int b[M]; int c[M]; int dfs(int aa,int bb) {if (aa<bb){int L=dfs(aa,(aa+bb)/2);int R=dfs((aa+bb)/2+1,bb);int num=L+R,tot=aa;int x=aa,y=(aa+bb)/2;int u=(aa+bb)/2+1,v=bb;while(x<=y||u<=v)if(u<=v&&(x==y+1||a[x]>a[u])){b[tot++]=a[u++];num+=y-x+1;//計算A B 中的逆序數}elseb[tot++]=a[x++];for(int i=aa;i<=bb;++i)a[i]=b[i];return num;}elsereturn 0; }int main() {int n;while (~scanf("%d",&n)){for( int i = 1 ; i <= n ; ++ i )scanf("%d",&a[ i ]);for ( int i = 1 ; i <= n ; ++ i )c[ i ] = a[ i ];int ans= dfs( 1, n );int mi =ans;for ( int i = 1 ; i < n ; ++ i ){ans+= n - 2*c[ i ] - 1;if ( ans< mi )mi=ans;}printf("%d\n",mi);}return 0; }

總結

以上是生活随笔為你收集整理的Minimum Inversion Number HDU - 1394(求一个数字环的逆序对+多种解法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。