首页 > 代码库 > bzoj3405:[Usaco2009 Open]Grazing2 移动牛棚

bzoj3405:[Usaco2009 Open]Grazing2 移动牛棚

思路:首先因为要让距离尽量大,所以奶牛1一定在1号牛棚,奶牛n一定在s号牛棚,然后考虑dp。

因为总距离为s-1,然后要使长度为d的段数尽量多,那么剩下的一定就是d+1的段数,也就是s-(n-1)*d。

然后f[i][j]表示保证前i个牛棚合法且前面长为d+1的段数为j的答案,然后第i个牛棚的位置其实就是(i-1)*d+j。

又因为第i-1个牛棚只可能是相隔d或d-1,所以有f[i][j]=min(f[i-1][j],f[i-1][j-1])+abs(a[i]-(i-1)*d-j)

答案就是f[n][m]。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1505
 
int n,s;
int a[maxn];
int f[maxn][maxn];
 
inline int read(){
    int x=0;char ch=getchar();
    for (;ch<‘0‘||ch>‘9‘;ch=getchar());
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘;
    return x;
}
 
inline void print(int x){
    if (x>=10) print(x/10);
    putchar(x%10+‘0‘);
}
 
int main(){
    n=read(),s=read();int d=(s-1)/(n-1),m=s-(n-1)*d;
    for (int i=1;i<=n;i++) a[i]=read();
    sort(a+1,a+n+1);
    memset(f,63,sizeof(f)),f[1][1]=a[1]-1;
    for (int i=2;i<=n;i++)
        for (int j=1;j<=m&&j<=i;j++)
            f[i][j]=min(f[i-1][j],f[i-1][j-1])+abs(a[i]-d*(i-1)-j);
    print(f[n][m]);
    return 0;
}

bzoj3405:[Usaco2009 Open]Grazing2 移动牛棚