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