/* dp[i]表示前i个数的最优解 dp[i]=min{ dp[j]+max[j+1,i] },sum[i]-sum[j]<=M 使用决策单调性:显然dp[i]是单调递增的 那么维护一个区间[j+1,i]关于a的递减单调队列q 对于a[q[1]]可以控制的决策范围是[j+1,q[1]],又因为决策单调性,所以这一段区间的最优解就是dp[j+1]+a[q[1]] 同理,遍历整个队列,可得后面每一段的最佳决策 */ #include<iostream> #include<queue> #include<cstdio> using namespace std; #define ll long long #define N 200005 ll n,M,a[N],sum[N],dp[N]; int main(){ cin>>n>>M; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++)if(a[i]>M){ puts("-1");return 0; } memset(dp,0x3f,sizeof dp);dp[0]=0; deque<int>q; deque<int>::iterator it,itt; int pos=1; for(int i=1;i<=n;i++){ while(sum[i]-sum[pos-1]>M)pos++; while(q.size()){//删前面 int p=q.front(); if(sum[i]-sum[p-1]>M)q.pop_front(); else break; } while(q.size()){//删后面 int p=q.back(); if(a[p]<=a[i])q.pop_back(); else break; } q.push_back(i); for(it=q.begin();it!=q.end();it++){ if(it==q.begin()){ dp[i]=min(dp[i],a[*it]+dp[pos-1]); }else { itt=it;itt--; dp[i]=min(dp[i],a[*it]+dp[*itt]); } } } cout<<dp[n]<<'\n'; }
来源:https://www.cnblogs.com/zsben991126/p/12512137.html