因爲滿分作法是單調棧優化DP,相對冷門,且複雜度依舊成謎,因此我選擇咕咕咕c++
費用提早,指的每每不是預先計算費用來保持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; }