1. 程式人生 > >【USACO 2010 Nov Gold】買飼料

【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;
}