看到这种一个状态 需要 O(n) 的转移的东西,我想,八成都得是这种题。
这道题
一个简单的的实现是
用 dp[i][j] 代表 到 第 i 步,最后用 j 机器生产最少消耗多少。
因为 j 最多连续生产 l 个,所以,只能从前面 i-l 之后转移过来。
转移方程看论文 点击打开论文。。。
但是论文中没有说清楚的是要是用几个单调队列。
我已开始以为要最多用 20 个 因为最多 5 条生产线,每条又可以被 其他 4 条所转移。
后来想明白了,没这个必要,虽然转移的时候,那个sum和我们的目标状态有关,我们依然可以只为要转移到的那条生产线准备一个单调队列。
这样,我们在转移之前就减去那条生产线到目前为止的总和。
还有两个细节问题。第一:一开始的转移是 不需要 K 滴 第二:每次转移要先更新本次的dp,然后再去更新单调队列。否则会挂前5个。
#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include <set>
#include <stack>
using namespace std;
#define READ freopen("acm.in","r",stdin)
#define WRITE freopen("acm.out","w",stdout)
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define PDI pair<double,int>
#define PDD pair<double,double>
#define MII map<int,int>::iterator
#define fst first
#define sec second
#define MS(x,d) memset(x,d,sizeof(x))
#define INF 0x3f3f3f3f
#define ALL(x) x.begin(),x.end()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ROOT 0,n-1,1
#define PB push_back
#define FOR(a,b,c) for(int a=b;a<c;a++)
#define MOD 1000000007
#define keyTree (ch[ ch[root][1] ][0])
#define MAX 200000
int dp[MAX][10];
int cost[MAX][10];
int m,n,K,L;
int sum[MAX][10];
struct deq
{
deque< PII > q;
void clear()
{
while(!q.empty())
q.pop_back();
q.push_back(PII(0,0));
}
int get(int i)
{
while(i-q.front().fst>L)
q.pop_front();
return q.front().sec;
}
void push(int i,int cost)
{
while(!q.empty()&&cost<=q.back().sec)
q.pop_back();
q.push_back(PII(i,cost));
}
}q[10];
int main()
{
READ;
scanf("%d%d%d%d",&m,&n,&K,&L);
{
MS(dp,0);
for(int i=0;i<10;i++)
q[i].clear();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&cost[j][i]),sum[j][i]=sum[j-1][i]+cost[j][i];
for(int i=1;i<=m;i++)// 步骤
{
for(int j=1;j<=n;j++)// 最后一个
{
int p=q[j].get(i);
dp[i][j]=sum[i][j]+p;
}
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if(j==k)
continue;
int cost=dp[i][j]-sum[i][k]+K;
q[k].push(i,cost);
}
}
}
int ans=INF;
for(int i=1;i<=n;i++)
ans=min(ans,dp[m][i]);
cout<<ans<<endl;
}
return 0;
}