POJ 3017.Cut the Sequence

题目:http://poj.org/problem?id=3017

AC代码(C++):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define INF 0x3f3f3f3f
#define eps 1e-5
typedef unsigned long long ull;
typedef long long ll;
typedef __int64 I64d;

using namespace std;

struct NODE {
	int val;
	int ind;
};

int n;
int a[100005];
ll m;
ll dp[100005];
NODE q[100005];
int head, tail;

int main() {
	while (cin >> n >> m) {
		bool flag = false;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			if (a[i] > m)flag = true;
		}
		if (flag) {
			cout << -1 << endl;
			continue;
		}
		dp[0] = 0;
		dp[1] = a[1];
		ll sum = a[1];
		int pos = 1;
		head = 0;
		tail = 1;
		q[0].val = a[1];
		q[0].ind = 1;
		for (int i = 2; i <= n; i++) {
			sum += a[i];
			while (sum > m&&pos < i) sum -= a[pos++];
			while (head < tail&&q[tail - 1].val < a[i])tail--;
			q[tail].val = a[i];
			q[tail++].ind = i;
			while (head < tail&&q[head].ind < pos)head++;

			dp[i] = dp[pos - 1] + q[head].val;
			for (int j = head; j < tail - 1; j++) {
				ll tmp = dp[q[j].ind] + q[j + 1].val;
				if (tmp < dp[i])dp[i] = tmp;
			}
		}
		cout << dp[n] << endl;
	}

	//system("pause");
}
总结: 利用单调队列优化的动态规划. dp[i] = min(dp[j] + max(a[j + 1], a[j + 2], ..., a[i])). j可以从pos开始, 而pos是满足a[pos] + ... + a[i]小于m的最小下标. 直接做会超时, 需要用到单调队列的优化, 即从a[pos]到a[i], 依次入队. 入队时, 把队尾所有小于入队数的数删掉, 再入队. 具体原理参照: http://blog.csdn.net/sdj222555/article/details/7996970

你可能感兴趣的:(poj)