• CF 1013E Hills——隔项转移的DP


    题目:http://codeforces.com/contest/1013/problem/E

    设 dp[ i ][ j ][ 0/1 ] 表示前 i 个位置,有 j 个山峰,第 i 个位置不是/是山峰的最小代价。

    dp[ i ][ j ][ 0 ] 可以从 dp[ i-1 ][ j ][ 0/1 ] 转移,从 1 转移的话要调整成 a[ i ] <= a[ i-1 ] ,因为  i-1 是山峰,所以它的高度一定还是原高度 a[ i-1 ],从 0 转移没有要求。

    dp[ i ][ j ][ 1 ] 需要从 dp[ i-2 ][ j-1 ][ 0/1 ] 转移,这样才能知道  i-2 位置的高度到底是多少。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    
    const int N=5005;
    int n,a[N],dp[N][N][2];
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      memset(dp,0x3f,sizeof dp);
      dp[0][0][0]=dp[1][0][0]=dp[1][1][1]=0;
      for(int i=2,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        int w=0; if(a[i]>=a[i-1])w=a[i]-a[i-1]+1;
        dp[i][j][0]=Mn(dp[i][j][0],dp[i-1][j][1]+w);
        if(!j)continue;
        dp[i][j][1]=dp[i-2][j-1][0];
        if(a[i-1]>=a[i])dp[i][j][1]+=a[i-1]-a[i]+1;
        w=0; if(a[i-1]>=a[i-2])w+=a[i-1]-a[i-2]+1;
        int tp=Mn(a[i-2]-1,a[i-1]);
        if(tp>=a[i])w+=tp-a[i]+1;
        dp[i][j][1]=Mn(dp[i][j][1],dp[i-2][j-1][1]+w);
          }
      /*
      for(int i=1,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        h[i][j][0]=a[i];
        int w;
        if(a[i]>=h[i-1][j][1])w=a[i]-h[i-1][j][1]+1;
        else w=0;
        if(dp[i-1][j][1]+w<dp[i][j][0])
          dp[i][j][0]=dp[i-1][j][1]+w,h[i][j][0]=h[i-1][j][1]-1;
    
        if(j)
          {
            dp[i][j][1]=dp[i-1][j-1][0];
            h[i][j][1]=a[i];
            if(h[i-1][j-1][0]>=a[i])
              dp[i][j][1]+=h[i-1][j-1][0]-a[i]+1;
          }
          }
      */
      for(int i=n+1>>1;i>=0;i--)
        {
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i][1]);
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i+1][0]);
        }
      for(int i=1,lm=n+1>>1;i<=lm;i++)
        printf("%d ",dp[n][i][0]);
      puts(""); return 0;
    }
    View Code

    自己原来还写了一个不是从 i-2 转移的,但带了一个 h[ i ][ j ][ 0/1 ] 表示当前的高度。这个 h[ ][ ][ ] 不参与转移,所以只是记录一下,不增加复杂度。但不知为何不对。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    
    const int N=5005;
    int n,a[N],dp[N][N][2],h[N][N][2];
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      memset(dp,0x3f,sizeof dp);
      dp[0][0][0]=0;
      for(int i=1,lm=i+1>>1;i<=n;i++,lm=i+1>>1)
        for(int j=0;j<=lm;j++)
          {
        dp[i][j][0]=dp[i-1][j][0];
        h[i][j][0]=a[i];
        int w;
        if(a[i]>=h[i-1][j][1])w=a[i]-h[i-1][j][1]+1;
        else w=0;
        if(dp[i-1][j][1]+w<dp[i][j][0])
          dp[i][j][0]=dp[i-1][j][1]+w,
            h[i][j][0]=Mn(h[i][j][0],h[i-1][j][1]-1);//Mn
    
        if(j)
          {
            dp[i][j][1]=dp[i-1][j-1][0];
            h[i][j][1]=a[i];
            if(h[i-1][j-1][0]>=a[i])
              dp[i][j][1]+=h[i-1][j-1][0]-a[i]+1;
          }
          }
      for(int i=n+1>>1;i>=0;i--)
        {
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i][1]);
          dp[n][i][0]=Mn(dp[n][i][0],dp[n][i+1][0]);
        }
      for(int i=1,lm=n+1>>1;i<=lm;i++)
        printf("%d ",dp[n][i][0]);
      puts(""); return 0;
    }
    View Code
  • 相关阅读:
    数据库中char、varchar、varchar2、nvarchar之间的关系
    Oracle中scott用户下基本表练习SQL语句
    判断一个数是否是素数
    阿里P7前端需要哪些技能
    react Native 踩坑记录
    流程节点(2018.7.31)
    在centos7下手工安装和配置Nginx
    微信公众号开发
    nodejs 实战
    数据库权限表的设计
  • 原文地址:https://www.cnblogs.com/Narh/p/10415626.html
Copyright © 2020-2023  润新知