POJ 3017 Cut the Sequence 单调队列优化DP

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/89843588

title

POJ 3017
AcWing 299
Description

Given an integer sequence a n { an } of length N N , you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the part is not greater than a given integer M M . You are to find a cutting that minimizes the sum of the maximum integer of each part.

Input

The first line of input contains two integer N ( 0 < N 100000 ) , M N (0 < N ≤ 100 000), M . The following line contains N integers describes the integer sequence. Every integer in the sequence is between 0 and 1 000 000 inclusively.

Output

Output one integer which is the minimum sum of the maximum integer of each part. If no such cuttings exist, output −1.

Sample Input

8 17
2 2 2 8 1 8 2 1

Sample Output

12

Hint

Use 64-bit integer type to hold M.

Source

POJ Monthly–2006.09.29, zhucheng

analysis

f [ i ] f[i] 为前 i i 个数取得的最小和,那么我们可以有递推公式:
f [ i ] = min 0 j < i k = j + 1 i A k M { f [ i ] f [ j ] + max j + 1 k i { A k } } f[i]=\min_{0 \le j < i 并且 \sum^{i}_{k=j+1} A_k\le M}\left\{f[i],f[j]+\max_{j+1 \le k \le i}\left\{A_k\right\}\right\}。
由于 a [ i ] > 0 { 1 i N } a[i]>0\left\{1\le i\le N\right\} ,那么可以发现 [ i ] [i] 必然是非递减的。

a [ k ] { j + 1 k i } a[k]\left\{j+1\le k\le i\right\} 中的最大值下标为 p o s pos

f [   ] f[\text{ }] 的非递减性, f [ j + 1 ] + a [ p o s ] f [ j + 2 ] + a [ p o s ] f [ p o s 1 ] + a [ p o s ] f[j+1]+a[pos]\le f[j+2]+a[pos]\le ··· \le f[pos-1]+a[pos]

所以我们取 f [ j + 1 ] + a [ p o s ] f[j+1]+a[pos] ,也就是说如果某一段到当前位置 i i 的最大值都一样,取最靠前的即可。

那么可以联想到单调队列,维护一个递减的队列,存的是符合要求的某一段的最大值。

但是需要注意!

队首元素不一定是最优的,由于队列的递减性质,队列中的所有元素都有可能组成最优解。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

struct Orz{ll val; int id;}q[maxn];
ll f[maxn];
int a[maxn];
int main()
{
	int n; ll m;
	while (~scanf("%d %lld",&n,&m))
	{
		bool flag=1;
		for (int i=1; i<=n; ++i)
		{
			read(a[i]);
			if (a[i]>m) flag=0;
		}
		if (!flag) { puts("-1"); continue; }

		int l=0,r=0,pos=1;
		ll sum=a[1];
		q[r].val=f[1]=a[1], q[r++].id=1;
		for (int i=2; i<=n; ++i)
		{
			sum+=a[i];
			while (sum>m && pos<i) sum-=a[pos],++pos;

			while (l<r && q[r-1].val<=a[i]) --r;
			q[r].val=a[i], q[r++].id=i;
			while (l<r && q[l].id<pos) ++l;

			f[i]=f[pos-1]+q[l].val;
			for (int j=l; j<r-1; ++j) f[i]=min(f[i],f[q[j].id]+q[j+1].val);
		}
		printf("%lld\n",f[n]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/89843588