题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=1742

https://www.lydsy.com/JudgeOnline/problem.php?id=3074

双倍经验题

题解

可以证明,奶牛吃掉的草一定是一段区间。

f[l][r][0/1]f[l][r][0/1]表示[l,r][l,r]这一段的草已经被吃完了,现在奶牛停在左边还是右边,所花费的最小代价。转移非常显然,时间复杂度O(n2)O(n^2)

代码

BZOJ 1742

#include <cstdio>
#include <cstring>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=1000;

int n,v[maxn+10];
long long f[maxn+10][maxn+10][2];

int main()
{
  n=read();
  v[0]=read();
  for(int i=1; i<=n; ++i)
    {
      v[i]=read();
    }
  std::sort(v+1,v+n+1);
  memset(f,63,sizeof f);
  int flag=0;
  for(int i=1; i<=n; ++i)
    {
      if(v[0]<=v[i])
        {
          for(int j=n; j>=i; --j)
            {
              v[j+1]=v[j];
            }
          v[i]=v[0];
          f[i][i][0]=f[i][i][1]=0;
          flag=1;
          break;
        }
    }
  if(flag==0)
    {
      v[n+1]=v[0];
      f[n+1][n+1][0]=f[n+1][n+1][1]=0;
    }
  for(int i=n+1; i; --i)
    {
      for(int j=i+1; j<=n+1; ++j)
        {
          f[i][j][0]=std::min(f[i][j][0],std::min(f[i+1][j][0]+1ll*(n-j+i+1)*(v[i+1]-v[i]),f[i+1][j][1]+1ll*(n-j+i+1)*(v[j]-v[i])));
          f[i][j][1]=std::min(f[i][j][1],std::min(f[i][j-1][1]+1ll*(n-j+i+1)*(v[j]-v[j-1]),f[i][j-1][0]+1ll*(n-j+i+1)*(v[j]-v[i])));
        }
    }
  printf("%lld\n",std::min(f[1][n+1][0],f[1][n+1][1]));
  return 0;
}

BZOJ 3074

#include <cstdio>
#include <cstring>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=1000;

int n,v[maxn+10];
long long f[maxn+10][maxn+10][2];

int main()
{
  n=read();
  for(int i=1; i<=n; ++i)
    {
      v[i]=read();
    }
  std::sort(v+1,v+n+1);
  memset(f,63,sizeof f);
  int flag=0;
  for(int i=1; i<=n; ++i)
    {
      if(0<=v[i])
        {
          for(int j=n; j>=i; --j)
            {
              v[j+1]=v[j];
            }
          v[i]=f[i][i][0]=f[i][i][1]=0;
          flag=1;
          break;
        }
    }
  if(flag==0)
    {
      v[n+1]=f[n+1][n+1][0]=f[n+1][n+1][1]=0;
    }
  for(int i=n+1; i; --i)
    {
      for(int j=i+1; j<=n+1; ++j)
        {
          f[i][j][0]=std::min(f[i][j][0],std::min(f[i+1][j][0]+1ll*(n-j+i+1)*(v[i+1]-v[i]),f[i+1][j][1]+1ll*(n-j+i+1)*(v[j]-v[i])));
          f[i][j][1]=std::min(f[i][j][1],std::min(f[i][j-1][1]+1ll*(n-j+i+1)*(v[j]-v[j-1]),f[i][j-1][0]+1ll*(n-j+i+1)*(v[j]-v[i])));
        }
    }
  printf("%lld\n",std::min(f[1][n+1][0],f[1][n+1][1]));
  return 0;
}