vijos 1243 生产产品 DP + 单调队列优化

LINK

题意:有1个产品,m个步骤编号为1~m。步骤要在n个机器人的手中生产完成。其中,第i个步骤在第j个机器人手中的生产时间给定为$T[i][j]$,切换机器人消耗cost。步骤必须按顺序,同一个机器人不能连续完成超过l个步骤。求完成所有步骤的最短时间是多少。其中$m<=10^5$,$n<=5$,$l<=5*10^4$

思路:这题用DP考虑易得一个转移方程$dp[i][j]=\min^{i-1}_{v=i-L}{(dp[v][x] + sum[i][j] - sum[v][j]) + cost}$其中$sum[i][j]$代表前i步由j完成的时间和

从转移式上来看,j为要转移到的状态,x为出发态,相当于对每个步骤v都做$O(n^2)$的转移,直接暴力枚举的话总复杂度是$O(l·m·n^2)$

当L足够大时,显然这样的算法不够快,可以注意到v的枚举是顺序的,而且$dp[v][x] -sum[v][j]$在给定x和j时也满足单调性的要求,即当$dp[v][x] -sum[v][j]$得到更小的值后,最优值为新得到的值,那么使用二维优先队列维护从x机器人转移到j机器人,范围为L的优先队列,队列存储其划分的位置,这样一来我们可在$O(1)$复杂度内获得L范围内的最小值(队列中元素最多进出一次),优化后复杂度$O(m·n^2)$

/** @Date    : 2017-07-19 19:25:11
  * @FileName: vijos 1243 单调性优化 DP 双端队列.cpp
  * @Platform: Windows
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int n, m, cost, l;
int sum[100500][8];
int dp[100500][8];

int main()
{
	while(cin >> m >> n >> cost >> l)
	{
		int x;
		for(int i = 1; i <= n; i++)
		{
			sum[0][i] = 0;
			for(int j = 1; j <= m; j++)
			{
				scanf("%d", &x);
				sum[j][i] = sum[j - 1][i] + x;
			}
		}

		deque<int >q[8][8];
		for(int i = 0; i <= m; i++)
			for(int j = 0; j <= n; j++)
				dp[i][j] = INF;
		for(int j = 0; j <= n; j++)
			dp[0][j] = 0;
		/*for(int i = 1; i <= n; i++)
			for(int k = 1; k <= n; k++)
				q[i][k].push_back(0);*/
		///////////////////////
		for(int i = 0; i <= m; i++)
		{
			for(int j = 1; j <= n; j++)//删除头不符合条件的
				for(int x = 1; x <= n; x++)//from
				{
					if(j == x)
						continue;
					while(!q[j][x].empty()
						&& i - l > q[j][x].front())
						q[j][x].pop_front();
				}

			for(int j = 1; j <= n; j++)//单独考虑j
				for(int x = 1; x <= n; x++)//from 从什么方向转移
				{
					if(j == x)
						continue;
					int v = 0;
					if(!q[j][x].empty())
						v = q[j][x].front();
					dp[i][j] = min(dp[v][x] - sum[v][j] + sum[i][j] + cost, dp[i][j]);
				}
			for(int j = 1; j <= n; j++)//删除尾不单调(不最优的)
				for(int x = 1; x <= n; x++)//from
				{
					if(j == x)
						continue;
					while(!q[j][x].empty()
						&&  dp[i][x] - sum[i][j] <=
						dp[q[j][x].back()][x] - sum[q[j][x].back()][j])
						q[j][x].pop_back();
					q[j][x].push_back(i);
				}
		}
		int ans = INF;
		for(int i = 1; i <= n; i++)
			ans = min(ans, dp[m][i]);
		printf("%d\n", ans - cost);
	}
    return 0;
}
时间: 2024-11-03 21:07:22

vijos 1243 生产产品 DP + 单调队列优化的相关文章

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

Vijos P1243 生产产品 (单调队列优化DP)

题意: 必须严格按顺序执行M个步骤来生产一个产品,每一个步骤都可以在N台机器中的任何一台完成.机器i完成第j个步骤的时间为T[i][j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完成了产品的L个步骤,下一个步骤就必须换一台机器来完成.问一个产品最短需要多长时间呢?(对于100%的数据,N<=5, L<=50000,M<=100000) 题意: 被高中生虐了~ 题意要求尽量缩短时间来完成一件产品,但是由于需

vijos P1243 生产产品(单调队列+DP)

P1243生产产品 描述 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产 品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N 台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的 时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机

Vijos 1243 生产产品 (优先队列优化的动态规划)

题意:中文题.不说了. 注意一些地方,机器的执行过程是没有顺序的,而且每个机器可以用多次.第一次执行的机器不消耗转移时间K. 用dp[i][j]表示第i个机器完成第j个步骤的最短时间,sum[j][i]表示第i个机器完成前j个步骤的时间. 比较容易想到一个朴素的状态转移方程: dp[i][j]=min{dp[k][j']+sum[j][i]-sum[j'][i]}+K  (j-j'<l),(i!=k) 这里状态是O(n*m),转移是O(n*l),一定会超时,需要优化. 方程变形得dp[i][j]

UESTC 594 我要长高 dp单调队列优化入门

//其实是个伪单调队列...渣渣刚入门 //戳这里:594 //dp[ i ][ j(现身高) ] = min(    dp[ i ][ k(现身高) ]  + fabs( j(现身高) - k(现身高) ) * C + ( j(现身高) - h[i](原身高) )  *( j(现身高) - h[i](原身高) )     ); 观察到可以单调队列优化,O(N * H * H)  —>  O(N * H) j >= k 时, dp[ i ][ j ] = min (    dp[ i ][ k

HDU 3401 Trade dp 单调队列优化

戳这里:3401 题意:给出第 i 天的股票买卖价格(APi,BPi),以及每天股票买卖的数量上限(ASi,BSi),要求任两次交易需要间隔 W 天以上,即第 i 天交易,第 i + W + 1 天才能再交易,求最多能赚多少钱 思路:dp[i][j] = max(dp[i - 1][j], max(dp[f][k] - (j - k) * APi[i]), max(dp[f][k] + (k - j) * BPi[i])); 从式子中观察出,若两天都持有股票数 j 时,之后的那一天所赚的钱不小于

P3084 [USACO13OPEN]照片Photo (dp+单调队列优化)

题目链接:传送门 题目: 题目描述 Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered from 1..N. Accordingly, he snapped M (1 <= M <= 100,000) photos, each covering a

【烽火传递】dp + 单调队列优化

题目描述 烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定的代价.为了使情报准确的传递,在 m 个烽火台中至少要有一个发出信号.现输入 n.m 和每个烽火台发出的信号的代价,请计算总共最少需要多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递! 输入格式 第一行有两个数 n,m 分别表示 n 个烽火台,在任意连续的 m 个烽火台中至少

vijos 1243 生产产品

貌似两年前联赛复习的时候就看过这题 然而当时大概看看了 感觉太难 便没有去做 如今再去做的时候 发现其实也并不容易 ------------------------------------------------------------------------- 这题首先是要处理一下不能在同一台机器上工作L个步骤 对于这一点 我们可以构造两个数组 f[i][j]表示在第i台机器上完成了第j个步骤 g[i][j]表示在第i台机器上完成了第j个步骤 且第j-1个步骤不是在第i台机器上完成的 这一个问