P4544 [USACO10NOV] Buying Feed G

rgw2010發表於2024-08-02

思路:

考慮動態規劃演算法。

定義 \(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;
}

相關文章