zoukankan      html  css  js  c++  java
  • 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
    ",cas,ans);
    128     }
    129     return 0;
    130 
    131 }
    AC代码
  • 相关阅读:
    python开发环境安装
    python文件I/O
    python字符串方法以及注释
    python列表
    php: Can't use function return value in write context
    Notice : brew install php70
    对web开发从业者的发展方向的思考
    关于微信跨号支付
    MySQL触发器写法
    MySQL慢查询日志
  • 原文地址:https://www.cnblogs.com/qswg/p/9325210.html
Copyright © 2011-2022 走看看