2018.10.23 vijo1243生产产品(单调队列优化dp)

传送门
这道单调队列真的有点难写啊。
方程感觉挺简单的。
f [ i ] [ j ] f[i][j] f[i][j]表示在第 i i i个车间结束前 j j j次步骤的最小代价。
然后用单调队列毒瘤优化一下就行了。
代码:

#include
using namespace std;
#define ll long long
#define fi first
#define se second
const int M=100005;
int m,n,L,hd[6][6],tl[6][6];
ll K,sum[6][M],f[6][M],ans=1e18;
pair<int,ll>q[6][6][M];
inline ll read(){
	ll ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int main(){
	m=read(),n=read(),K=read(),L=read();
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)sum[i][j]=sum[i][j-1]+read();
	if(n==1)return cout<<sum[1][m],0;
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)q[i][j][hd[i][j]=tl[i][j]=1]=make_pair(0,-K);
	for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j){
			bool flag=0;
			for(int k=1;k<=n;++k){
				if(j==k)continue;
				while(i-q[j][k][hd[j][k]].fi>L)++hd[j][k];
				if(!flag||f[j][i]>q[j][k][hd[j][k]].se)flag=1,f[j][i]=q[j][k][hd[j][k]].se;
			}
			f[j][i]+=K+sum[j][i];
			if(i==m)ans=min(ans,f[j][i]);
		}
		for(int j=1;j<=n;++j){
			for(int k=1;k<=n;++k){
				if(j==k)continue;
				while(hd[k][j]<=tl[k][j]&&q[k][j][tl[k][j]].se>=f[j][i]-sum[k][i])--tl[k][j];
				q[k][j][++tl[k][j]]=make_pair(i,f[j][i]-sum[k][i]);
			}
		}
	}
	cout<<ans;
	return 0;
}

你可能感兴趣的:(#,单调队列,#,dp)