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

 

posted on 2019-02-21 22:00  Narh  阅读(172)  评论(0编辑  收藏  举报

导航