标签:
题意:给你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