洛谷P1880 四边形不等式优化石子合并

题意:

给定圆周上的 n n n堆石子,每一堆有 w i w_{i} wi个石头,合并两堆的代价为两堆的石头总数之和,问合并所有堆为一堆的最小代价。

O ( n 2 ) O(n^2) O(n2)做法:

转移方程形如 d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] , d p [ k + 1 ] [ j ] ) + w [ i ] [ j ] dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j] dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j]的转移方程,可以用四边形不等式优化,将 O ( n 3 ) O(n^3) O(n3)的复杂度降为 O ( n 2 ) O(n^2) O(n2)其中必须是 m i n min min w [ i ] [ j ] w[i][j] w[i][j]表示处理区间为 [ i , j ] [i,j] [i,j]的贡献。

四边形不等式:

l ≤ l ′ ≤ r ′ ≤ r l \leq l' \leq r' \leq r llrr,有 w [ l ′ ] [ r ′ ] ≤ w [ l ] [ r ] w[l'][r'] \leq w[l][r] w[l][r]w[l][r] w [ l ] [ r ′ ] + w [ l ′ ] [ r ] ≤ w [ l ] [ r ] + w [ l ′ ] [ r ′ ] w[l][r']+w[l'][r]\leq w[l][r]+w[l'][r'] w[l][r]+w[l][r]w[l][r]+w[l][r]成立,就有如下的不等式成立:

s [ l ] [ r − 1 ] < = s [ l ] [ r ] < = s [ l ] [ r + 1 ] s[l][r-1]<=s[l][r]<=s[l][r+1] s[l][r1]<=s[l][r]<=s[l][r+1],其中 s [ l ] [ r ] s[l][r] s[l][r]表示为 [ l , r ] [l,r] [l,r]的最佳决策点,即使 d p [ l ] [ k ] + d p [ k + 1 ] [ j ] dp[l][k]+dp[k+1][j] dp[l][k]+dp[k+1][j]最小的 k k k

那么,我们计算 d p [ i ] [ j ] dp[i][j] dp[i][j]时,我们只需要在 [ s [ i ] [ j − 1 ] , s [ i + 1 ] [ j ] ] [s[i][j-1],s[i+1][j]] [s[i][j1],s[i+1][j]]中枚举 k k k即可,假设我们在 j − i j-i ji恒定的情况下枚举,也就是按顺序枚举 d p [ i ] [ j ] , d p [ i + 1 ] [ j + 1 ] , d p [ i + 2 ] [ j + 2 ] , . . . , d p [ n − ( j − i + 1 ) + 1 ] [ n ] dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n-(j-i+1)+1][n] dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n(ji+1)+1][n]

我们分别需要在

[ s [ i ] [ j − 1 ] , s [ i + 1 ] [ j ] ] [s[i][j-1],s[i+1][j]] [s[i][j1],s[i+1][j]]

[ s [ i + 1 ] [ j ] , s [ i + 2 ] [ j + 1 ] ] [s[i+1][j],s[i+2][j+1]] [s[i+1][j],s[i+2][j+1]]

. . . . . ..... .....

[ s [ n − ( j − i + 1 ) + 1 ] [ n − 1 ] , s [ n − ( j − i + 1 ) + 1 − 1 ] [ n ] ] [s[n-(j-i+1)+1][n-1],s[n-(j-i+1)+1-1][n]] [s[n(ji+1)+1][n1],s[n(ji+1)+11][n]]

中枚举 k k k,发现这些区间首尾相连,总长度为 s [ n − l + 2 ] [ n ] − s [ 1 ] [ l − 1 ] + n − l + 1 ≤ n + n = 2 n s[n-l+2][n]-s[1][l-1]+n-l+1\leq n+n=2n s[nl+2][n]s[1][l1]+nl+1n+n=2n

所以我们给定计算区间的长度,可以在 O ( n ) O(n) O(n)时间内计算完所有的这个长度的 d p dp dp值,枚举长度也是 O ( n ) O(n) O(n),总复杂度是 O ( n 2 ) O(n^2) O(n2)

最大值:

性质: d p [ i ] [ j ] dp[i][j] dp[i][j]的最大值总是在合并端点处取得,也就是 m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] ) max(dp[i+1][j],dp[i][j-1]) max(dp[i+1][j],dp[i][j1])

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int n,w[205],sum[205],dp[205][205],s[205][205];
int inf=0x3fffffff,ans=inf;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i];
        sum[i]=sum[i-1]+w[i];
        s[i][i]=i;
    }
    for(int i=n+1;i<=2*n;i++)
    {
        w[i]=w[i-n];
        s[i][i]=i;
        sum[i]=sum[i-1]+w[i];
    }
    auto getvalue=[&](int l,int r)
    {
        return sum[r]-sum[l-1];
    };    
    for(int i=1;i<=2*n;i++)
    {
        // for(int j=1;j<=2*n;j++) dp[i][j]=inf;
        dp[i][i]=0;
    }
    for(int i=2*n-1;i>=1;i--)
        for(int j=i+1;j<=2*n;j++) dp[i][j]=min(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
    for(int i=1;i<=n;i++) ans=min(ans,dp[i][i+n-1]);
    cout<<ans<<endl;
    for(int i=2*n-1;i>=1;i--)
        for(int j=i+1;j<=2*n;j++) dp[i][j]=max(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
    ans=-1;
    for(int i=1;i<=n;i++) ans=max(ans,dp[i][i+n-1]);
    cout<<ans;
    return 0;    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值