题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=1742
https://www.lydsy.com/JudgeOnline/problem.php?id=3074
双倍经验题
题解
可以证明,奶牛吃掉的草一定是一段区间。
设表示这一段的草已经被吃完了,现在奶牛停在左边还是右边,所花费的最小代价。转移非常显然,时间复杂度。
代码
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;
}