您的位置:首页 > 其它

1705: [Usaco2007 Nov]Telephone Wire 架设电话线

2017-09-21 07:19 501 查看
题目链接

题目大意:现给出n个数wi,每个数不超过m,对于每个数都可以花费x2的代价使其增加x(每个数只能进行一次),操作完成后任意两个相邻的数x、y会产生|x−y|×C的代价,求最小总代价

题解:h[i][j]表示考虑了前i个数,最后一个数大小为j的最小总代价,每次只需枚举下一个数的大小即可,时间复杂度O(nm2)



可以发现后面是关于h[i−1][k]+k的后缀min和关于h[i−1][k]−k的前缀min,可以枚举i之后预处理

枚举j,整个式子便可O(1)求出,时间复杂度O(nm)

我的收获:拆式子!

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

#define INF 0x3f3f3f3f
const int M=100005,H=100;

int n,c,P,Q;
int a[M],f[M][105],C[105],D[105];

void solve()
{
memset(f,0x3f,sizeof(f));
for(int j=a[1];j<=H;j++) f[1][j]=(j-a[1])*(j-a[1]);
for(int i=2;i<=n;i++){
C[0]=D[H+1]=INF;
for(int j=1;j<=H;j++) C[j]=min(C[j-1],f[i-1][j]-j*c);
for(int j=H;j>=1;j--) D[j]=min(D[j+1],f[i-1][j]+j*c);

for(int j=a[i];j<=H;j++){
P=min(C[j]+j*c,D[j]-j*c);
Q=(j-a[i])*(j-a[i]);
f[i][j]=P+Q;
}

}
}

void work()
{
solve();
int ans=INF;
for(int i=a
;i<=H;i++) ans=min(ans,f
[i]);
printf("%d\n",ans);
}

void init()
{
cin>>n>>c;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
}

int main()
{
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: