Sicily:1351.Multi-key Sorting

Sicily : 1351. Multi-key Sorting

Sicily上的这道题,我刚开始做以为是要除去一个序列中连续且重复的片段,但后来发现

去重之后的序列依然可能不是最短的,比如说:

序列:{ 1,2,3,1,2,1,2 }

这个序列,消去连续且重复的片段之后变为:

         { 1,2,3,1,2 }

而实际上,序列:3、1、2才是真正的最短序列。

       但是其实,我们离最终的解法已经相隔不远了,其实解决这个问题的关键词已经确定——那就是“去重”,只不过如何“去重”还有待我们考究。

在此,我先给出本题的解法:

  从序列的最后一个开始遍历整个序列,将重复遍历的元素删去,最后剩下的序列就是最短序列。

那么,为什么这样的方法是可行的呢?

首先,我们举一个非常简单的例子:

假如:C=2 ,N=3 (列数为2,操作序列长度为3),且最初的序列是:

{ 1,2,1}  …… ①

按照之前给出的解法,最短序列应为: { 2,1 }  ……②

  因为①中最后一个元素为1,所以我们最后对矩阵的第1列进行了排序。我们最后的排序结果很大程度上取决于这最后一次排序,因此如果我们要找到等价的序列,那么首先按照这个序列排序后的矩阵的最后一列必须得是升序的。在这里,倘若最后一行每个元素都是不同的,那么其实这个等价序列只要是{ 1 }就可以搞定了,但是因为我们是对任意一个矩阵而言的,所以第1列中可能会有相同元素,那么问题的关键就在于这些相同元素所在的那几行该如何排序了,实际上:这些相同元素所在的那几行应该如何排序取决于①的子序列{1、2}中对其他列的排序情况(因为只有对除了最后一列的其他列进行排序,才能改变最后一列中相同元素的相对顺序)因此序列①中的第一个元素1是不起作用的,可以删去。

  至此,我们已经完成了对“去重”的分析,那么是不是只要按照这种策略来去重所得到序列就一定是最短的呢?显然是的,因为每一个不重复的数字都代表着要对那一列进行一次排序,而题目的要求是对所有矩阵均成立,所以倘若去掉某个数字,那么就意味着我们对这一列未曾进行过排序,没有了这一次排序可能就会导致某一列的相同元素的顺序会出错,导致与原序列不等价。

  由此,我们可以把上面这个例子进行推广:

  序列中如果出现{ … , a, … , a , …} ,即序列中出现两个相同元素,那么同上文中所述的原理,我们从右到左遍历,删去重复出现的元素,所得到的序列即为最短的等价序列。那么,为什么要从右到左遍历,其实根据上面的分析,细心的读者可能已经发现右边的元素的优先级是很明显会更高一些的,毕竟越往右的元素越能对最终排序后的矩阵产生更大的影响。

下面附上代码:

#include <bits/stdc++.h>



using namespace std ;



int a[3000005] , b[3000005] ; 

int visit[1000005] ; 

int main () 

{

    int c , n , k ; 

    while(scanf("%d %d" , &c , &n) != EOF)

    {

        for(int i=0 ; i<n ; i++)

            scanf("%d" , &a[i]) ;

        k = 0 ; 

        for(int i=n-1 ; i>=0 ; i--)

        {

            if(!visit[a[i]])

            {

                b[k++] = a[i] ;

                visit[a[i]] = 1 ; 

            }                 

        }

        printf("%d\n" , k) ;

        printf("%d" , b[k-1]) ;  

        for(int i = k-2 ; i >= 0 ; i--)

            printf(" %d" , b[i]) ; 

        printf("\n") ;

        memset(visit , 0 , sizeof(visit)) ;  

    }

    return 0 ;

}

 

你可能感兴趣的:(sort)