zoukankan      html  css  js  c++  java
  • USACOSorting a ThreeValued Sequence

    http://ace.delos.com/usacoprob2?a=kPNDMRfiMdD&S=sort3

    这题初看似乎比较麻烦,仔细想想,也就这么回事了。

    手工模拟一下排序的过程,然后对比排序前后的数列,很容易发现,交换只发生在以下情况:1.交换一次能够使得两个数都到达最终位置(这个显然的);2.两次交换能够使得三个数到达最终位置。只能有这两种情况了。

    位置:           1 2 3 4 5 6 7 8 9

    分析一下样例:2 2 1 3 3 3 2 3 1

    最终位置是:   1 1 2 2 2 3 3 3 3

    位置2、3交换一次,位置5、7交换一次,可以使两对数到达最终位置,此时:

    位置:           1 2 3 4 5 6 7 8 9

                       2 1 2 3 2 3 3 3 1

    最终位置是:  1 1 2 2 2 3 3 3 3

    位置1,4,9交换两次,此时:

    位置:           1 2 3 4 5 6 7 8 9

                      1 1 2 2 2 3 3 3 3

    最终位置是:  1 1 2 2 2 3 3 3 3

    任务完成,共交换4次。

    至于两次交换使得3个数到达最终位置,具体的证明如下:

    首先需要指明:a,b,c三个数之间可以有若干个其他数字,这里只取他们的相对位置。

    假设a,b,c(a<b<c)三个数都不在他们的最终位置上(若有一个在最终位置上,归结到情况1),则只有以下两种情况:

    最终位置:a  b  c

    case1:    b  c   a

    case2:    c   a   b

    对于case1,交换b,c,然后交换a,c,两次可以完成;

    对于case2,交换c,a,然后交换b,c,同样两次可以完成。

    若a,b,c有两个数是相等的,则必定可以归结到情况1。这里不作证明。

    到此,做法已经很明显了。下面给出步骤:

    1.将数列排序,记录不在最终位置上的个数,用sn[i][j]表示在i的位置上有sn[i][j]个j(这里i和j都表示1,2,3其中一个);

    2.统计在情况1的交换次数,取sn[i][j]和sn[j][i]的较小值;

    3.统计情况2的交换次数,除去了情况1,若在1段和2段中发现有不合理的数字,则必须交换2次了,具体自己理解。

    具体实现看代码:

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    using namespace std;
    
    int sn[4][4]={0};
    int f[4]={0};
    int a[100000];
    int main()
    {
        freopen("sort3.in","r",stdin);
        freopen("sort3.out","w",stdout);
        int n;
        cin>>n;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            f[a[i]]++;          //排序
        }
        //这一段代码求数组sn[i][j]
        int ll=1,rr=f[1];
        for (int i=1;i<=3;i++)
        {
            for (int j=ll;j<=rr;j++)
                sn[i][a[j]]++;
            ll=rr+1; rr=rr+f[i+1];
        }
        //情况1的统计,一次交换的条件是取sn[i][j]、sn[j][i]的较小值
        int min1=min(sn[1][2],sn[2][1]),min2=min(sn[1][3],sn[3][1]),
            min3=min(sn[2][3],sn[3][2]);
        int sum=min1+min2+min3;
        //除去情况1,剩下的一定是情况2了
        sum+=(sn[1][2]-min1+sn[1][3]-min2)*2;
        cout<<sum<<endl;
        return 0;
    }

    这题其实挺水的。。。。附上我的战绩:

    sort3

  • 相关阅读:
    对象在hibernate中的状态
    Hibernate核心对象
    Hibernate入门步骤及概念
    Hibernate事务、缓存和连接池
    ORACLE数据库入门再在屋里坐会
    CREATE FUNCTION 的用法
    远程操作win的命令窗口
    获取谷歌浏览器cookie的两种方法
    使用selenium.webdriver.common.desired_capabilities获取浏览器日志
    Appium自动测试框架常用API
  • 原文地址:https://www.cnblogs.com/ay27/p/2734232.html
Copyright © 2011-2022 走看看