单调队列-首尾相连数组的最大子数组和

题目描述:

给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的。数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选)。

输入:

输入包含多个测试用例,每个测试用例共有两行,第一行是一个整数n(1=<n<=100000),表示数组的长度,第二行依次输入n个整数(整数绝对值不大于1000)。

输出:

对于每个测试用例,请输出子数组和的最大值。

样例输入:
6
1 -2 3 5 -1 2
5
6 -1 5 4 -7
样例输出:
10
14



#include<stdio.h>
#include<math.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include <iostream>
using namespace std;

const int MAX = 110000 * 2;

int sum[MAX];
struct Q {
	int id, v;
} q[MAX];
int front;
int rear;
void push(int id, int v) {
	rear++;
	q[rear].id = id;
	q[rear].v = v;
	while (rear - 1 >= front && q[rear - 1].v > q[rear].v) {
		rear--;
		q[rear] = q[rear + 1];
	}
}

int query(int id) {
	while (front <= rear && q[front].id < id) {
		front++; //队列头超出范围的删除掉
	}
	if (front > rear)
		return 0;
	return q[front].v;
}

void print_q() {
	for (int i = 0; i <= rear; i++)
		cout << q[i].id << ":" << q[i].v << "   ";
	cout << endl;
}
int main() {
	int n;
	int i;
	freopen("in.txt", "r", stdin);
	while (scanf("%d", &n) != EOF) {
		sum[0] = 0;
		for (i = 1; i <= n; i++) {
			scanf("%d", &sum[i]);
			sum[i + n] = sum[i];
		}
		for (i = 1; i <= 2 * n; i++)
			sum[i] += sum[i - 1];
		rear = -1;
		front = 0;
		push(0, 0);
		int ans = 0;
		for (i = 1; i <= 2 * n; i++) {
			//print_q(); 打印

			//tmp即为 i 到 i-n+1 之间的 最大字段和
			int tmp = sum[i] - query(i - n + 1); //查询得间距不超过n的最小前缀

			//打印
			//cout << i << " " << i - n + 1 << "  " << query(i - n + 1) << "  "<< sum[i] << endl;
			if (tmp > ans)
				ans = tmp;
			push(i, sum[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}


你可能感兴趣的:(单调队列-首尾相连数组的最大子数组和)