标签:
题意:给你n个数,求划分的区间所有的最大值之和(划分条件就是这个区间之和小于m),使其最小
首先很容易想到dp,公式 dp【i】= min(dp【i】,dp【j】+max(a【j+1】+。。。a【i】))
这是O(n^2)的复杂度
那么维护一个单调递减的序列的话,每次求的就是单调队列里面满足条件的那些元素,然后根据dp递推公式求解
Hint :用多组交的话会wA
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define N 111111
const ll inf = 1111111111111;
ll sum;
ll a[N];
int n;
ll m;
int que[N];
ll dp[N];
ll slove(){
sum = 0;
int k = 0;
int l = 0;
int r = -1;
dp[0] = 0;
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
if(a[i]>m) return -1;
sum+=a[i];
while(sum>m) sum-=a[++k]; //求满足区间和小于m的区间左端
while(l<=r&&a[que[r]]<=a[i]) --r;//更新单调队列,即那些比a【i】小的元素都可以舍弃掉了,因为之后不会再用了
que[++r] = i;
while(l<=r&&que[l]<=k) l++;
dp[i] = inf;
int h = k;
// printf(" h ---%d\n l--%d--r---%d\n%d\n",h,l,r,que[r]);
for(int j=l;j<=r;j++){
ll tmp = dp[h] + a[que[j]];
if(tmp < dp[i]) dp[i] = tmp;
h = que[j];
}
}
return dp[n];
}
int main(){
scanf("%d%I64d",&n,&m);
printf("%I64d\n",slove());
}版权声明:都是兄弟,请随意转载,请注明兄弟是谁
标签:
原文地址:http://blog.csdn.net/u013076044/article/details/46940941