【BZOJ】P2448 挖油

区间dp+决策单调性

题目链接

part1.朴素dp

(dp[l][r])表示l到r这个区间最坏情况下的最小花费。

那么考虑在([l,r])中任选一个点k挖,此时有两种情况:

1.k点有油,那么后续代价就是(dp[k+1][r])

2.k点没有油,那么后续代价就是(dp[l][k-1])

显然,为了使情况最坏,我们要在(dp[k+1][r])(dp[l][k-1])中取最大值。

要使最坏情况下花费最小,我们要在所有k中取最小值。

那么,转移方程就是:

[dp[l][r]=min{max{dp[l][k-1],dp[k+1][r] }+A[k]} kin[l+1,r-1] ]

其中(A[i])表示在点i勘测是否有油的花费。

这样,就有一个(O(n^3))朴素dp了,期望得分30分。


part2.决策单调性优化

我们要的是([l,r])的最小值,所以应该是维护单调递增的队列。

但还有一个问题,转移方程中有(max{dp[l][k-1],dp[k+1][r] }),我们要想办法把这个max消掉。

那如何消去max呢?

我们维护一个k,使得(dp[l][k-1])刚好大于(dp[k+1][r])或者(dp[k+1][r])刚好大于(dp[l][k-1])

现在,我们只需证明k是具有单调性的就可以了。

首先,不难发现这样一个性质:对于任意的l,r,都有(dp[l][r]le dp[l][r+1])

我们以维护(dp[l][k-1])刚好大于(dp[k+1][r])为例。

那么,假设l,k固定,随着r的不断增大,(dp[k+1][r])也会不断增大,而(dp[l][k-1])不变,因此k肯定会不断向右移

同理,维护(dp[k+1][r])刚好大于(dp[l][k-1])时,k肯定也会不断向左移

于是,我们在维护最小值的同时再不断弹出队头不合法的元素,这样就保证转移一定是从(dp[l][k-1])或者(dp[k+1][r])转移过来的。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,A[2010],dp[2010][2010],Q[2010][2010],head[2010],tail[2010];
//要以每个点都作为l和r的情况各开一个单调队列
//但是由于dp中l是第一层循环,那么枚举一个l后就不会在遍历到了,因此可以把所有点作为l的情况公用一个单调队列
//那么开n+1个单调队列就可以了
int calcl(int l,int r,int k){
    return dp[l][k-1]+A[k];
}
int calcr(int l,int r,int k){
    return dp[k+1][r]+A[k];
}
int main(){
    memset(dp,63,sizeof(dp));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&A[i]);
    for(int i=1;i<=n;i++)head[i]=1;
    for(int l=n;l>=1;l--){
        head[0]=1;
        tail[0]=0;
        dp[l][l]=A[l];
        Q[0][++tail[0]]=l;
        for(int r=l+1;r<=n;r++){
            while(head[0]<=tail[0]&&calcl(l,r,Q[0][head[0]])<calcr(l,r,Q[0][head[0]]))head[0]++;
            while(head[0]<=tail[0]&&calcl(l,r,r)<calcl(l,r,Q[0][tail[0]]))tail[0]--;
            Q[0][++tail[0]]=r;
            while(head[r]<=tail[r]&&calcr(l,r,Q[r][head[r]])<calcl(l,r,Q[r][head[r]]))head[r]++;
            while(head[r]<=tail[r]&&calcr(l,r,l)<calcr(l,r,Q[r][tail[r]]))tail[r]--;
            Q[r][++tail[r]]=l;
            dp[l][r]=min(calcl(l,r,Q[0][head[0]]),calcr(l,r,Q[r][head[r]]));
        }
    }
    cout<<dp[1][n];
    return 0;
}
原文地址:https://www.cnblogs.com/SillyTieT/p/11636304.html