思路:
考慮動態規劃演算法。
定義 \(dp_{i,j}\) 表示達到第 \(i\) 家商店時共買了 \(j\) 噸飼料的最小花費,那麼我們可以列舉到達上一家店的飼料數 \(k\):
\[dp_{i,j} = (x_i-x_{i-1}) \times j^2 + \min\limits_{k=j-f_{i-1}}^j dp_{i-1,k} + c_{i-1} \times (j-k)
\]
可以將和 \(i-1\) 與 \(i\) 有關的提到一邊,這樣可以方便轉移:
\[dp_{i,j} = (x_i-x_{i-1}) \times j^2 + c_{i-1} \times j + \min\limits_{k=j-f_{i-1}}^j dp_{i-1,k} - k \times c_{i-1}
\]
注意到對於區間 \([j-f_{i-1},j]\),當 \(j\) 增加時,右端點增加 \(1\),左端點也增加 \(1\),那麼我們可以使用單調佇列維護這個範圍的最小值。
時間複雜度為 \(O(MK)\)。
完整程式碼:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=505,M=10010,INF=1e18;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct Node{
ll x,y,z;
bool operator<(const Node&rhs)const{
if(x!=rhs.x)
return x<rhs.x;
return z<rhs.z;
}
}G[N];
ll n,x,m,l,r,head=0,tail=1;
ll a[N],b[N],c[N],Q[M];
ll dp[N][M];
bool End;
int main(){
// open("A.in","A.out");
memset(dp,0x3f,sizeof(dp));
m=read(),x=read(),n=read();
for(int x,y,z,i=1;i<=n;i++){
x=read(),y=read(),z=read();
G[i]={x,y,z};
}
sort(G+1,G+n+1);
for(int i=1;i<=n;i++){
a[i]=G[i].x;
b[i]=G[i].y;
c[i]=G[i].z;
}
a[n+1]=x;
dp[1][0]=0;
for(int i=2;i<=n+1;i++){
head=1,tail=0;
for(int j=0;j<=m;j++){
while(dp[i-1][j]-j*c[i-1]<=dp[i-1][Q[tail]]-Q[tail]*c[i-1]&&head<=tail)
tail--;
while(Q[head]<j-b[i-1]&&head<=tail)
head++;
Q[++tail]=j;
dp[i][j]=dp[i-1][Q[head]]+(a[i]-a[i-1])*j*j+c[i-1]*(j-Q[head]);
}
}
write(dp[n+1][m]);
cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
return 0;
}