zoukankan      html  css  js  c++  java
  • p1951

    第一眼看到以为也是贪心(毕竟毕竟喜欢贪心的题)。

    本题中要求把一个数列改成单调的数列,允许全为一个数。求改动的最少的次数。

    最基础的想法是先求出每个位置以前包括自己1、2、3的个数sum1[i],sum2[i],sum3[i]。然后再枚举一的截止位点和二的截止位点,次数就可以直接求出。

    公式如下(i取0到n,f取i到n)

    1 2 3递增序列
    ans=min(n-sum1[i]-sum2[f]+sum2[i]-sum3[n]+sum3[f],ans);
    3 2 1递减序列
    ans=min(n+sum1[f]-sum1[n]+sum2[i]-sum2[f]-sum3[i],ans);

    这样下来复杂度是n^2,我不知道咋算的以为不会超时,以为应该是正解了吧,但被打脸了。(但是由于过水的数据还拿了90分)

    想正解的过程中先想到的是空间换时间,然后一个动态规划的写法就很快出炉了:

    在递增的时候维护ans[1][i] 、ans[2][i]、ans[3][i]分别表示第i个数为1、2、3时改动的个数,那么有这样的转移方程(minn返回三者的最小值)

    //自己理解吧
    ans[1][i]=ans[1][i-1];
    ans[2][i]=min(ans[1][i-1],ans[2][i-1]);
    ans[3][i]=minn(ans[1][i-1],ans[2][i-1],ans[3][i-1]);
    
    if(o[i]==1)
    {
        ans[2][i]++;
        ans[3][i]++;
    }
    if(o[i]==2)
    {
        ans[1][i]++;
        ans[3][i]++;
    }
    if(o[i]==3)
    {
        ans[1][i]++;
        ans[2][i]++;
    }

    相似的,递减的时候可以这样弄

    ans[3][i]=ans[3][i-1];
    ans[2][i]=min(ans[3][i-1],ans[2][i-1]);
    ans[1][i]=minn(ans[3][i-1],ans[2][i-1],ans[1][i-1]);
    
    if(o[i]==3)
    {
        ans[2][i]++;
        ans[1][i]++;
    }
    if(o[i]==2)
    {
        ans[3][i]++;
        ans[1][i]++;
    }
    if(o[i]==1)
    {
        ans[3][i]++;
        ans[2][i]++;
    }

    最后的答案是两次循环后在ans[1/2/3][n]中取最小值。

    本题AC

  • 相关阅读:
    数据存储检索之B+树和LSM-Tree
    Kylin构建Cube过程详解
    关于maven打包乱码报错问题解决
    很详尽KMP算法 转载
    计算机源码反码补码
    Lombok实现链式编程 转载
    java适配器模式
    ubuntu卸载软件步骤(转)
    JMeter压测的使用
    @valid注解的使用(转载)
  • 原文地址:https://www.cnblogs.com/qywyt/p/9230773.html
Copyright © 2011-2022 走看看