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代码

 

posted @ 2018-07-17 18:46  强势围观  阅读(1801)  评论(0编辑  收藏  举报