Vijos 1243 生产产品[单调队列优化dp]

好吧...作为我A掉的第一道单调队列优化dp....在高中生的OJ上....而且我调了一个半小时样例....然后很神奇的1A = =...

诶 这题果断比多校8的1005难啊...min里面的东西这么奇葩的...又 k 又 p 又 j 地...开始我以为只要一个队列, 搞了半天发现应该要N个队列... = =...写出来好神奇....

转移方程什么的详见代码吧....要碎了....

总结下:

形如 d[i] = min(f[k]) 的转移方程(  k随i不降, f为可以根据 k 在常数时间内确定的唯一常数 ). 可以采用单调队列优化, 把求min的O(n)时间, 优化到O(1).

具体操作过程一般为:

设 k=[low, high].

1/ 把f[high]丢进deq. (维护deq, 若deq不为空, 先从尾部pop掉不符合单调的元素)

2/ 从首部找元素作为min(f[k]). (元素应满足k的范围, 即序号大于low, 不满足的pop掉).


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

#define MAXN 7
#define MAXM 100002
#define MAXL 50002

int d[MAXM][MAXN];	//d[i][j] 表示 第i个步骤由第j人完成所需的最短时间.
//	转移方程:  d[i][j] = min{ d[k][p]+cost[j][i]-cost[j][k] +K | k=[i-L, i-1], k>=1, p=[1, N], p!=j } .
//		单调队列优化:	 d[i][j] = min{ d[k][p]-cost[j][k] | k=[i-L, i-1], k>=1, p=[1, N], p!=j } +cost[j][i] + K.
//	d[0][p] = -K;

int cost[MAXN][MAXM];		//	cost[i][j], 表示 第 i 个人, 完成 第 1~j 步骤 需要的时间和.

int deq[MAXM][MAXN];
int front[MAXN], tail[MAXN];
int f[MAXM][MAXN];	//min(f)

int main()
{
	memset(d, 0, sizeof(d));
	memset(cost, 0, sizeof(cost));
	int m=Rint(), n=Rint(), K=Rint(), L=Rint();
	FOR(i, 1, n)
	{
		FOR(j, 1, m)
		{
			int t = Rint();
			cost[i][j]=cost[i][j-1]+t;	//前缀和
		}
	}
	FOR(i, 1, n)
	{
		d[0][i] = -K;
	}
	//front = tail = 1;	//下标从1开始
	FOR(i, 1, n)
	{
		front[i]  = tail[i] = 1;
	}
	FOR(i, 1, m)		//	d[i] = min(d[k][p]-cost[k]) + cost[i] + K
	{
		FOR(j, 1, n)
		{
			//	把	f[i-1] 丢进 deq

			f[i-1][j] = INF;
			FOR(p, 1, n)		//	min(d[k]-cost[k])
			{
				if(p == j) continue;
				//f[i] = min(f[i], d[k][p]-cost[j][k]);
				//f[i] = min(f[i], d[i][p]-cost[j][i]);		
				f[i-1][j] = min(f[i-1][j], d[i-1][p]-cost[j][i-1]);		//由于 k<=i-1, 所以这里用 i-1, d[i][p]还没全算出来
			}
			//bug(i-1);bug(j);bug(f[i-1][j])<<endl;
			//bug(f[deq[tail[j]-1][j]][j])<<endl;
			while(front[j]<tail[j] && f[i-1][j]<f[deq[tail[j]-1][j]][j]) tail[j]--;
			deq[tail[j]++][j] = i-1;		//这里是i-1 不是i..............!!!!

			//	由deq 求得  min(f[k]), k=[i-L, i-1]

			//int low = i-L<1? 1: i-L;
			int low = i-L<0? 0: i-L;			// 由于有边界, 下标扩展为0
			//int high = i-1;
			//bug(deq[front[j]][j])<<endl;
			while(deq[front[j]][j]<low) front[j]++;
			//bug(deq[ front[j] ][j])<<endl;
			int minx = f[ deq[ front[j] ][j] ][j];
			d[i][j] = minx + cost[j][i] + K;
			//bug(minx)<<endl;
			//bug(i);bug(j);bug(d[i][j])<<endl;
		}
	}
	int minx = INF;
	FOR(i, 1, n)
	{
		minx = min(minx, d[m][i]);
	}
	printf("%d\n", minx);
}

发布了179 篇原创文章 · 获赞 5 · 访问量 20万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览