BZOJ 1742 [Usaco2005 nov]Grazing on the Run 边跑边吃草 + BZOJ 3074 [Usaco2013 Mar]The Cow Run

题目链接

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

代码

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值