BZOJ 3405: [Usaco2009 Open]Grazing2 移动牛棚 dp

来源:互联网 发布:淘宝荣耀官方旗舰店 编辑:程序博客网 时间:2024/06/09 18:02

3405: [Usaco2009 Open]Grazing2 移动牛棚

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 45  Solved: 25
[Submit][Status][Discuss]

Description

  约翰有N(2≤N≤1500)头奶牛,S(N≤S≤1,000,000)个一字排开的牛棚.相邻牛棚间的距离恰好为1.
奶牛们已经回棚休息,第i只奶牛现在待在牛棚Pi.如果两只奶牛离得太近,会让奶牛们变得很暴躁.所以约翰想给一些奶牛换一个棚,让她们之间的距离变得尽量大,并且尽管接近.令d=Trunc((s-1)/(n-1))
所以约翰希望最终的奶牛的状态是:两只相邻奶牛间的距离与d之差不超过1,而且让尽量多的间距等于d.因此,对于4只奶牛8个棚的情况,1,3,5,8或1,3,6,8这样的安置情况是允许的,而1,2,4,7或1,2,4,8这样的情况是不允许的.帮助约翰移动奶牛,让所有奶牛的移动距离之和最小,同时让最终的安置情况符合约翰心意.

Input

    第1行输入N和S,接下来N行一行输入一个Pi.

Output

    一个整数,表示最小的移动距离和.

Sample Input

5 10
2
8
1
3
9

Sample Output

4

HINT

   最终移成1,3,5,8,10.

BJ太水了。。这都没想到

思路:首先因为要让距离尽量大,所以奶牛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<ctime>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<bitset>#include<queue>#include<map>#include<set>using namespace std;typedef long long ll;inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}inline void print(int x){    if (x>=10) print(x/10);    putchar(x%10+'0');}const int N=1510,M=1001000;int a[N],f[N][N];int main(){    int 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,0X3f,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;}


阅读全文
0 0