牛客网 货物分组 60分(费用提早的DP)

费用提早的DP

因为满分作法是单调栈优化DP,相对冷门,且复杂度依旧成谜,因此我选择咕咕咕c++

谈一谈60分的\(O(n^2)\)作法

费用提早,指的每每不是预先计算费用来保持DP的最优子结构性质。相反,它破坏了最优子结构的性质,除了最后咱们须要的答案,其它DP出的答案都是错的。好比此题,咱们提早考虑其在i==n时最大贡献,致使最终的答案除了dp[n]是正确的,其他都是错的git

也就是说,费用提早是一种在DP方程不知足最优子结构的状况下,咱们只须要某一个点的答案,就单独考虑此前状态对该点的贡献,从而达到无视后效性的效果,经常使用与区间DP或分段DP的优化优化

先看\(O(n^3)\)的DP方程:spa

\(f[n][m]=min{f[n-1][k]+m∗(s(m)−s(k))+max(m,k+1)−min(m,k+1)}\)code

其中s表示前缀和get

咱们再来考虑\(O(N^2)\)的DP,考虑直接计算\(dp[n]\)input

先不考虑最大值最小值的影响,咱们发现it

\(dp[n]=1*(s[a]-s[0])+2*(s[b]-s[a])+...+i*(s[n]-s[c])\)ast

化简可得class

\(dp[n]=-s[0]-s[a]-s[b]-...-s[c]+i*s[n]\)

也能够写做

\(dp[n]=-s[0]+s[n]-s[a]+s[n]-s[b]+s[n]-...-s[c]+s[n]-s[n]+s[n]\)

故每一个\(dp[i]\)对最终答案的贡献为\(s[n]-s[i]\),而后在DP中考虑最大最小值带来的影响便可

\(dp[i]=min(dp[i],dp[j-1]+max(j,i)-min(j,i)+s[n]-s[i])\)

\(dp[0]=s[n]\)

代码

#include<bits/stdc++.h>
//#pragma GCC optimize(3)
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast")
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define fo(i,a) for(int i=0;i<a;++i)
#define int long long
#define il inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

const int inf=0x3f3f3f3f3f3f3f3f,N=1e5+10;

int n,m,a[N],dp[N],g[N],sum[N];

il void read(int &x){
    x=0;char c=getchar(),f=1;
    while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

signed main(){
    //freopen("input.txt","r",stdin);
    read(n),read(m);
    go(i,1,n) read(a[i]);
    go(i,1,n) sum[i]=sum[i-1]+a[i];
    mem(dp,0x3f);
    dp[0]=sum[n];
    int tot,mx,mn;
    go(i,1,n){
        tot=0,mx=0,mn=inf;
        com(j,i,1){
            tot+=a[j];
            mx=max(mx,a[j]),mn=min(mn,a[j]);
            if(tot>m) break;
            dp[i]=min(dp[i],dp[j-1]+mx-mn);
        }
        dp[i]+=sum[n]-sum[i];
    }
    printf("%lld",dp[n]);
    return 0;
}
相关文章
相关标签/搜索