架设电话线(bzoj1705)

问题 D: 架设电话线(bzoj1705)
时间限制: 1 Sec 内存限制: 128 MB
提交: 23 解决: 11
[提交][状态]
题目描述
最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线。 新的电话线架设在已有的N(2 <= N <= 100,000)根电话线杆上, 第i根电话线杆的高度为height_i米(1 <= height_i <= 100)。 电话线总是从一根电话线杆的顶端被引到相邻的那根的顶端 如果这两根电话线杆的高度不同,那么FJ就必须为此支付 C*电话线杆高度差(1 <= C <= 100)的费用。当然,你不能移动电话线杆, 只能按原有的顺序在相邻杆间架设电话线。Farmer John认为 加高某些电话线杆能减少架设电话线的总花费,尽管这项工作也需要支出一定的费用。 更准确地,如果他把一根电话线杆加高X米的话,他得为此付出X^2的费用。 请你帮Farmer John计算一下,如果合理地进行这两种工作,他最少要在这个电话线改造工程上花多少钱。
输入

  • 第1行: 2个用空格隔开的整数:N和C * 第2…N+1行: 第i+1行仅有一个整数:height_i

输出

  • 第1行: 输出Farmer John完成电话线改造工程所需要的最小花费

样例输入
5 2

2

3

5

1

4

输入说明:

一共有5根电话线杆,在杆间拉电话线的费用是每米高度差$2。

在改造之前,电话线杆的高度依次为2,3,5,1,4米。
样例输出
15

输出说明:

最好的改造方法是:Farmer John把第一根电话线杆加高1米,把第四根加高2米,

使得它们的高度依次为3,3,5,3,4米。这样花在加高电线杆上的钱是$5。

此时,拉电话线的费用为$2*(0+2+2+1) = $10,总花费为$15。
林肯是大头:
http://www.accoders.com/problem.php?cid=1965&pid=3
思路:
动规,f[i][j]表示第i根电线杆高度变为j时的费用
转移方程:
f[i][j]=MIN f[i-1][k]+(j-h[i])^2+cabs(j-k)
很容易发现时间复杂度为O(n
hh)太大了
于是用单调队列优化
abs可化为
c
j-ck(j>=k)//代码中第一个循环
c
k-c*j(j<k)
至今没弄明白哪里有单调队列
注意:见代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxh=100+10;
const int maxn=1e5+10;
int f[maxn][maxh];//i->  高度
int a[maxn];      //F省略一维就错了? 
int n,c; 
int main()
{
	memset(f,0x7f,sizeof(f));
	int m=0;
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]),m=max(m,a[i]);//m->最大高度  加高是为了减小与较高的柱子的差距 
	for(int i=a[1];i<=m;i++)        //而超过最高后不如加高至最高或最高-1的情况 
	f[1][i]=(i-a[1])*(i-a[1]);//初始化F[1][j]-> 只有增高的情况 
	for(int i=2;i<=n;i++)
	{
		//printf("i%d\n",i);
		int minn=0x7fffffff;
		for(int j=a[i-1];j<=m;j++)//
		{
			//printf("j1 %d\n",j);
			minn=min(minn,f[i-1][j]-c*j);// 此时J为I-1时的J 
			if(j>=a[i]) f[i][j]=minn+c*j+(j-a[i])*(j-a[i]);//此时J为I时的J
		}
		minn=0x7fffffff;
		for(int j=m;j>=a[i];j--)//
		{
			minn=min(minn,f[i-1][j]+c*j);//
			f[i][j]=min(minn-c*j+(j-a[i])*(j-a[i]),f[i][j]);//
		}
	}
	int ans=0x7fffffff;
	for(int i=1;i<=maxh;i++)
	ans=min(f[n][i],ans);
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值