/* 交的时候没什么信心会AC,结果AC了,挺高兴的。 如果之前能确定算法没问题,应该自信点~不熟练还是~ 题解: 先得dp方程:f[i]=f[j]+max(x[j+1],x[j+2],...,x[i]),其中j<i,x[j+1]+x[j+2]+...+x[i]<=m; 可以用n^2级的dp算法手工模拟一下,发现其中最优策略的规律,考虑m的影响,最值的区间范围等等,然后单调队列搞起~ 网路上的代码太长了,就没怎么参考了。 */ #include <cstdio> #include <iostream> #include <cstring> #include <deque> using namespace std; typedef __int64 LL; const int NN=1000005; const LL INF=(LL)1<<62; int n; LL m,x[NN],f[NN]; int q[NN],front=1,rear=0; LL cut() { int k=0,kk; LL cnt=0; f[0]=0; for (int i=1; i<=n; i++) { scanf("%lld",&x[i]); if (x[i]>m) return -1; //无法划分 cnt+=x[i]; while (cnt>m) cnt-=x[++k]; //k满足x[k+1]+x[k+2]+...+x[i]<=m,且x[k]+x[k+1]+...+x[i]>m,即[k+1,i]是i能划分到的最靠前的区间 while (rear>=front && x[q[rear]]<=x[i]) rear--; //维护队列 q[++rear]=i; while (rear>=front && q[front]<=k) front++; //队首元素太'远',删 f[i]=INF; kk=k; for (int j=front; j<=rear; j++) //队列优化后的dp过程 { LL tmp=f[kk]+x[q[j]]; if (tmp<f[i]) f[i]=tmp; kk=q[j]; //kk表示当前最值存在的区间范围是[kk+1,i] } } return f[n]; } int main() { scanf("%d%lld",&n,&m); printf("%I64d\n",cut()); return 0; }