【USACO 2010 Nov Gold】买饲料

Description

约翰开车回家,准备顺路买点饲料了 。回家的路程一共有E公里,一路上会经过K家商店,第i家店里有Fi 吨饲料,售价为每吨Ci元。约翰打算一共买N吨饲料,可以保证所有商店的库存和不会少于N。除了购买饲料要钱,运送饲料要花油钱,约翰的卡车上如果装着X吨饲料,那么他行驶一公里会花掉X^2元,行驶D公里需要DX^2元。已知第i家店距离起点有Xi公里,那么约翰在哪些商店买饲料运回家,才能做到最省钱呢?

Input

第一行:三个整数:N,E和K,1 ≤ N ≤ 10000,1 ≤ E ≤ 500,1 ≤ K ≤ 500
第二行到N + 1行:第i + 1行有三个整数:Xi,Fi和Ci,0 < Xi< E,1 ≤ Fi≤ 10000,1 ≤ Ci≤ 10^7

Output

单个整数:表示购买及运送饲料的最小费用

Sample Input

2 5 3

3 1 2

4 1 2

1 1 1

Sample Output

9

Hint

(在离家较近的两家商店里各购买一吨饲料,则花在路上的钱是1 + 4 = 5,花在店里的钱是2 + 2 = 4)。

显然是个背包,发现可以单调队列优化,需要注意的是限制条件,如果大了的话要提前更新。

#include<bits/stdc++.h>
using namespace std;
const int Maxn=505;
#define int long long
int f[Maxn][Maxn*20];
int l,r,q[Maxn*20];
int N,E,K;
struct info{
	int x,f,c;
	bool operator <(const info&rhs)const{
		return x<rhs.x;
	}
}s[Maxn];
signed main(){
	scanf("%lld%lld%lld",&K,&E,&N);
	for(int i=1;i<=N;++i){
		scanf("%lld%lld%lld",&s[i].x,&s[i].f,&s[i].c);
		s[i].f=min(s[i].f,K);
	}
	sort(s+1,s+N+1);
	memset(f,63,sizeof(f));
	f[0][0]=0;
	for(int i=1;i<=N;++i){
		q[l=r=1]=0;
		int jt=0,jq=1;
		for(;jq<=K;++jq){
			while(l<=r&&f[i-1][jq]+jq*jq*(s[i].x-s[i-1].x)-jq*s[i].c<=f[i-1][q[r]]+q[r]*q[r]*(s[i].x-s[i-1].x)-q[r]*s[i].c){
				for(;jt<=q[r];++jt){//来提前更新,因为i-1大的不能i小的 
					while(l<r&&jt-q[l]>s[i].f)++l;
					f[i][jt]=f[i-1][q[l]]+q[l]*q[l]*(s[i].x-s[i-1].x)+(jt-q[l])*s[i].c;		
				}
				--r;
			}
			q[++r]=jq;
		}
		for(;jt<=K;++jt){
			while(l<r&&jt-q[l]>s[i].f)++l;
			f[i][jt]=f[i-1][q[l]]+q[l]*q[l]*(s[i].x-s[i-1].x)+(jt-q[l])*s[i].c;
		}
	}
	cout<<f[N][K]+K*K*(E-s[N].x)<<endl;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值