• BZOJ2448 挖油


    题目链接:戳我

    看完题目我们有一个很明显的DP方程可以想出——(dp[i][j]=min{max(dp[i][k-1],dp[k+1][j])+a[k]}),这个时间复杂度是(O(n^3))的。

    解释一下为什么是取max,因为我们是要从最坏的情况转移而来。

    但是这个时间复杂度对于此题的数据范围显然不太合适,之后我们就应该想到。。。DP优化!

    但是DP优化有那么多种,这道题到底应该怎么解决呢?

    我们考虑如何把最后一层枚举k的那个循环拿掉。首先是需要解决取max的问题,就是我们需要知道什么时候到底从哪一个决策点转移过来是最坏的情况呢?

    我们观察上面列出的DP转移式子,可以发现所有转移来自的情况也不外乎是两种,一种是包含i的,我们可以称之为“左半部分"。一种包含j的,我们可以称之为”右半部分“。首先需要知道,对于一个区间[i,j],我们将j右移。如果选择“左区间”,这个右端点是一定不会向左移动;选择“右区间”,左端点也不会向右移动。那么这样就具有了单调性。普通的遍历转移显然很慢,需要另外一个(O(n)),需要把这一层去掉,所以我们现在就是把这些情况附加到枚举区间右端点(即j)的时候。

    怎么附加呢?我们可以开n+1个单调队列。其中q[i][]表示固定i的时候,选择”左区间“,该”左区间“的右端点。每次更换i的时候需要重置,左右指针分别为l[0],r[0]。q[j][]表示固定j,选择”右区间“,该”右区间“的左端点,左右指针分别为l[j],r[j]。

    我们维护一个单调上升的优先队列。转移的时候,如果不满足从最坏情况转移过来的约束,就把队首弹出。最后计算dp[i][j]的时候,直接在表示“选择左右区间”的两个队列里面弹出队首(最小值)即可。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define MAXN 2010
    using namespace std;
    int n;
    int dp[MAXN][MAXN],a[MAXN],q[MAXN][MAXN],l[MAXN],r[MAXN];
    inline int calc1(int x,int y,int mid){return dp[x][mid-1]+a[mid];}
    inline int calc2(int x,int y,int mid){return dp[mid+1][y]+a[mid];}
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	memset(dp,0x3f,sizeof(dp));
    	for(int i=n;i>=1;i--)
    	{
    		dp[i][i]=a[i];
    		l[0]=r[0]=0;
    		q[0][++r[0]]=i;
    		for(int j=1+i;j<=n;j++)
    		{
    			while(l[0]<=r[0]&&calc1(i,j,q[0][l[0]])<calc2(i,j,q[0][l[0]])) l[0]++;
    			while(l[0]<=r[0]&&calc1(i,j,j)<calc1(i,j,q[0][r[0]])) r[0]--;
    			q[0][++r[0]]=j;
    			while(l[j]<=r[j]&&calc2(i,j,q[j][l[j]])<calc1(i,j,q[j][l[j]])) l[j]++;
    			while(l[j]<=r[j]&&calc2(i,j,i)<calc2(i,j,q[j][r[j]])) r[j]--;
    			q[j][++r[j]]=i;
    			dp[i][j]=min(calc1(i,j,q[0][l[0]]),calc2(i,j,q[j][l[j]]));
    		}
    	}
    	printf("%d
    ",dp[1][n]);
    	return 0;
    }
    
  • 相关阅读:
    javascript规范
    freemarker规范
    java代码质量
    使用ESP8266制作一个微型气象站
    热风枪焊接表面贴装元件的工具和技巧
    MCUXpresso IDE:导入Kinetis Design Studio工程
    基于LPCXpresso54608开发板创建Embedded Wizard UI应用程序
    STM32 LoRaWAN探索板B-L072Z-LRWAN1入门指南
    LPCXpresso54608开发板中文用户手册
    STM32 LoRaWAN探索板B-L072Z-LRWAN1中文用户手册
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10354856.html
Copyright © 2020-2023  润新知