• 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

  • 相关阅读:
    SQList基础+ListView基本使用
    Git本地上传口令
    记住用户名和登录密码+虚拟机没有root权限解决办法
    API+gir上传错误解决办法
    界面跳转+信息传递+AS中如何将ADV转移到其他盘中
    界面跳转
    Android学习——ListView
    开课第一周周总结
    体温上报APP——班级统计
    体温上报APP——打印
  • 原文地址:https://www.cnblogs.com/qywyt/p/9230773.html
Copyright © 2020-2023  润新知