【USACO 2010 Nov Gold】買飼料
阿新 • • 發佈:2018-12-18
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; }