hihoCoder挑戰賽34 B題(快速求第k輪冒泡排序的結果)


官方題解:https://media.hihocoder.com/contests/challenge34/tutorials-previewed.pdf

題目鏈接:http://hihocoder.com/problemset/problem/1781

題意問對於給定序列A,是否存在一個整數k, 使得A冒泡k輪后變成序列B.

這題一種做法是像官方題解一樣寫個計算區間最值的數據結構。

而我是另一種做法,通過的逆序數 來判斷A怎樣能變化到B。

例子

首先我舉一個例子:

對於序列  A      

8 7 5 1 9 2 6 4 3

其每個位置的逆序數是:

0 1 2 3 0 4 3 5 6       (*)

接着對A冒泡一輪,得到:

7 5 1 8 2 6 4 3 9

這時每個位置的逆序數是:

0 1 2 0 3 2 4 5 0      (**)

那么序列(*)和序列(**) 直接有啥聯系呢?

(**)=(*)每個數減-1,並向左平移一格 ,且最多減到0.

證明

現在來證明,每冒泡一輪 所有位置的逆序數-1,並向左移一格。

引理1:對於每輪冒泡排序,若一個位置的前面存在比他大的數,  則他一定會他前面的某個比他大的數進行有且僅有一次交換

這個引理大家自已腦補一下,應該很容易理解是對的。

引理2:若一個位置的前面存在比他大的數,則個位置的逆序數大於0

這個廢話,我就不解釋了。

證:因為任意一個逆序大於1位置,都與比他大的數交換一次,交換后首先逆序數必然減一,其次,交換后為位置肯定前移1格。 故結論成立。

 

解題思路

有了這個規律,顯然我可以直接O(n)求出任意一輪A的逆序數 與B比較。

再利用【逆序數和】每輪的都會遞減的單調性。就可以用二分比較逆序數和的方式,在O(n logn)時間定位b.

或者做一個O(n)預處理,算出n-1輪中,每輪的逆序數和,這樣可以把查詢的時間復雜度降低至O(n)

當然因為還要對數據進行O(n logn)離散化和求逆序數的原因,所以無論你寫哪種最終復雜度都是O(n logn)。

  1 #include<stdio.h>
  2 #include<vector>
  3 #include<algorithm>
  4 #include<string.h>
  5 #include<stack>
  6 #include<math.h>
  7 using namespace std;
  8 #define lowbit(x) (x&(-x))
  9 int a[100005],b[100004];
 10 int s1[200005],s2[100005];
 11 int c[200005];
 12 int N=200005;
 13 int cot[200005];
 14 int getsum(int x)
 15 {
 16     int sum=0;
 17     while(x)
 18     {
 19         sum+=c[x];
 20         x-=lowbit(x);
 21     }
 22     return sum;
 23 }
 24 void add(int x)
 25 {
 26     while(x<=N)
 27     {
 28         c[x]++;
 29         x+=lowbit(x);
 30     }
 31 }
 32 vector<int>que;
 33 int getid(int x)
 34 {
 35     return lower_bound(que.begin(),que.end(),x)-que.begin()+1;
 36 }
 37 void cal(int n,int a[],int ans[])
 38 {
 39     int i;
 40     memset(c,0,sizeof(c));
 41     for(i=1; i<=n; i++)
 42     {
 43         ans[i]=(i-1)-getsum(a[i]);
 44         add(a[i]);
 45     }
 46 }
 47 int main()
 48 {
 49     int i,j,t,n,x,y,k,op,q;
 50     long long m;
 51    // freopen("1.in","r",stdin);
 52     //freopen("2.out","w",stdout);
 53     scanf("%d",&t);
 54     for(int cas=1; cas<=t; cas++)
 55     {
 56         scanf("%d",&n);
 57         memset(s1,0,sizeof(s1));
 58         memset(cot,0,sizeof(cot));
 59         que.clear();
 60         for(i=1; i<=n; i++)
 61         {
 62             scanf("%d",&a[i]);
 63             que.push_back(a[i]);
 64         }
 65         for(i=1; i<=n; i++)
 66         {
 67             scanf("%d",&b[i]);
 68             que.push_back(b[i]);
 69         }
 70         sort(que.begin(),que.end());
 71         m=unique(que.begin(),que.end())-que.begin();
 72         que.resize(m);
 73         int ans=-1;
 74         for(i=1; i<=n; i++)
 75         {
 76             a[i]=getid(a[i]);
 77             b[i]=getid(b[i]);
 78         }
 79         cal(n,a,s1);
 80         cal(n,b,s2);
 81         long long sum=0;
 82         k=0;
 83         for(i=1; i<=n; i++)
 84         {
 85             cot[s1[i]]++;
 86             k=max(s1[i],k);
 87             sum+=s2[i];
 88             printf("%d ",s1[i]);
 89         }
 90         m=0;
 91         for(i=k+1; i>0; i--)
 92         {
 93             m=m+cot[i];
 94             sum-=m;
 95             if(sum<=0)
 96             {
 97                 break;
 98             }
 99         }
100         if(sum==0)
101         {
102             i--;
103             for(j=1; j<=n; j++)
104             {
105                 if(max(s1[j+i]-i,0)!=s2[j])
106                 {
107                     break;
108                 }
109             }
110             if(j>n)
111             {
112                 sort(a+1,a+n+1);
113                 sort(b+1,b+n+1);
114                 for(j=1; j<=n; j++)
115                 {
116                     if(a[j]!=b[j])
117                     {
118                         break;
119                     }
120                 }
121                 if(j>n)
122                 {
123                     ans=i;
124                 }
125             }
126         }
127         printf("Case #%d: %d\n",cas,ans);
128     }
129     return 0;
130 
131 }
AC代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM