
分析:
考虑初级的dpO(N^3^)
code:
for(ri K=1;K<=n;K++) for(ri i=1;i<=n;i++){ for(ri j=i-1;j>=1;j--) if(sum[i]-sum[j]<=w) dp[i][K]=min(dp[j][K-1]+K*(sum[i]-sum[j])+querymax(j+1,i)-querymin(j+1,i),dp[i][K]);
考虑能不能降维
发现这个K很多事
想到把K这一维删去
这里就要用到费用提前算的思想了
补充:费用提前算
https://www.luogu.org/problem/P2365
分析:
考虑最原始的dp:
f[i,j]=min{f[k,j-1]+(s×j+sumT[i])×(sumF[i]-sumF[k])}(0<=k<i)
复杂度N^3^
把费用提前算:将以后会算上的,先加上,除掉后效性
f[i]=min{f[k]+sumT[i]×(sumF[i]-sumF[k])+s*(sumF[n]-sumF[k])}
这题数据也就N^2^,其实这题还可以斜率优化,当然懒得说了
回到正题
dp[i,K]=min(dp[j,K-1]+K*(sum[i]-sum[j])+querymax(j+1,i)-querymin(j+1,i),dp[i,K])
经过变换:
dp[i]=min{dp[j]+(sum[i]-sum[j])+querymax(j+1,i)-querymin(j+1,i)+sum[n]-sum[i]};
后面的相比前面的系数差1
这样是N^2^的,还是不行怎么办
发现还可以单调队列优化
code by std:
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e5+10; int t,n,wi,q[maxn]; ll sum[maxn],stmn[maxn][30],stmx[maxn][30],f[maxn]; inline void stwk(){ for(int i=1;i<=t;i++) for(int j=1;j+(1<<(i-1))<=n;j++){ stmn[j][i]=min(stmn[j][i-1],stmn[j+(1<<(i-1))][i-1]); stmx[j][i]=max(stmx[j][i-1],stmx[j+(1<<(i-1))][i-1]); } } inline ll ask(int l,int r){ int k=log2(r-l+1); ll minn=min(stmn[l][k],stmn[r-(1<<k)+1][k]),maxx=max(stmx[l][k],stmx[r-(1<<k)+1][k]); return maxx-minn; } int main() { scanf("%d%d",&n,&wi); t=log2(n)+1; for(int x,i=1;i<=n;i++){ scanf("%d",&x); sum[i]=(ll)sum[i-1]+x;stmn[i][0]=(ll)x;stmx[i][0]=(ll)x; } stwk(); memset(f,0x3f,sizeof(f)); f[0]=0;int l=0,r=0; for(int i=1;i<=n;i++){ while(l<=r && sum[i]-sum[q[l]]>wi) l++; for(int j=l;j<=r;j++) f[i]=min(f[i],f[q[j]]+sum[n]-sum[q[j]]+ask(q[j]+1,i)); while(l<=r && f[i]<=f[q[r]]) r--; q[++r]=i; } printf("%lld\n",f[n]); return 0; }