斜率优化dp学习

参考:传送门

在做dp的时候一个状态i需要从0~i-1的状态中选择最优状态来进行转移,而单纯的这样转移,时间复杂度是O(n^2)的,使用斜率优化dp可以将时间复杂度降低到O(n)或者O(nlogn)。

如果状态i从一个状态转移j比从另一个状态k转移好,那么他们之间肯定会存在一个包含i,j,k的不等式,如果这个不等式能够化成左边只和j,k有关的斜率,右边只和i又管,那么就是j,k之间的某种斜率满足关于i的一个不等式就证明j状态转移比k状态好。这样,我们用队列维护一个凸包,就可以。如果不等式右边根据i状态的递增或者递减的那么直接改变队头,O(1)就可以,如果不是递增或递减,那么我们不改变队头,在队头和队尾之间二分斜率,满足那个斜率的后一个点就是最好的转移点,O(logn)。

例题:hdu3507

#include
using namespace std;
typedef long long ll;
const int maxn = 5e5+100;
ll c[maxn];
ll dp[maxn];
ll que[maxn];
ll getX(int a,int b)
{
    return c[b] -c[a];
}
ll getY(int a,int b)
{
    return ( dp[b] + c[b] * c[b] ) - ( dp[a] + c[a] * c[a] ); 
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        c[0] = 0;
        dp[0] = 0;
        int head = 0,tail = 1;
        que[0] = 0;
        for(int i = 1;i<=n;i++)
        {
            scanf("%lld",&c[i]);
            c[i] += c[i-1];
            while(head=getY(que[tail-1],i) * getX(que[tail-2],que[tail-1]))--tail;
            que[tail++] = i;
        }
        printf("%lld\n",dp[n]);
    }
}

例题:牛客

#include
using namespace std;
typedef long long ll;
const int maxn = 2e5+100;
ll a[maxn],b[maxn],que[maxn];
ll getX(int k,int j)
{
    return j - k;
}
ll getY(int k,int j)
{
    return (j * a[j] - b[j]) - (k * a[k] - b[k]);
}
bool check(int x2,int x1,ll t)
{
    return (x2 * a[x2] - b[x2]) - (x1 * a[x1] - b[x1] ) > t * (x2 - x1);
}
int main()
{
    int n;
    scanf("%d",&n);    
    a[0] = b[0] = 0;
    int head = 0,tail = 1;
    que[0] = 0;
    ll ans = -1e18;
    for(int i = 1;i<=n;++i)
    {
        scanf("%lld",&a[i]);
        b[i] = i * a[i] + b[i-1];
        a[i] += a[i - 1];
        int l = 1,r = tail-1,mid,tmpAns = 0;
        while(l<=r)
        {
            mid = (l+r)>>1;
            if(check(que[mid],que[mid-1],a[i]))
            {
                tmpAns = mid;
                l = mid + 1;
            }
            else r = mid - 1;
        }
        ans = max(ans,(b[i] - b[que[tmpAns]]) - (a[i] - a[que[tmpAns]])*que[tmpAns]);
        
        while(head+1=getX(que[tail-1],i)*getY(que[tail-2],que[tail-1]))--tail;
        que[tail++] = i;
    }
    printf("%lld\n",ans);
}

 

你可能感兴趣的:(动态规划)