杭电ACM3415——Max Sum of Max-K-sub-sequence

一开始,看到这题,以为是最大连续子序列和的问题,写出了代码,提交了,WR,找了一些测试数据,结果发现这个算法并不能将所以的序列的解求出,只是满足一部分序列。

百度了一下,知道了要用单调队列来求解。

单调队列,也就是队列中必然是单调递减的或者递增的。而这题使用的是单调递增的队列。

单调队列使用的是双向队列,队尾队头都可以删除元素,只能从队尾插入元素。

比如求解一个数列{1  ,2  ,5 ,3, 4, 6}的最长的递增序列的长度。

首先,1入队,队列中有 1。 接下来2比1 大,2入队,队列为 1 ,2

接下来5比2大,5入队,队列为1, 2, 5.

接下来3比5小,删除5,3再与新的队尾比较,3比2大,将3入队,队列为1 ,2, 3。

以此类推:最后队列为 1, 2, 3, 4, 6。

而杭电3415这一题,是求一个环状的数列的最大连续序列的和,序列长度不大于K。数列的第一项和最后一项相邻。

很多人一开始的想法就是DP,可是DP并不能解决,这个我前面已经讲到了。

输入序列的长度N,和最大序列的长度为K。

因为数列是环状的,所以将数组扩大一倍,输入时,a[i] = a[i + N](1 <= i <= N);这样就解决了环状的问题。

题目是求最大连续序列的和,所以用一个数组sum来存前i个数的和(1 <= i <= 2 * N),sum[i] = sum[i - 1] + a[i].

这样问题求解的最大连续子序列和(ans)就变成了求解sum数组中在长度不超过K的情况下,ans = sum【j】- sum【i】。sum【i】为sum中相对最小的,sum【j】为相对最大的,j - i  + 1 <= K(因为有长度限制)。这样不断更新ans。这里的队列不是单调递增的,那就等价于 拿每一个sum数组的每一个与它的前面的每一个相减来更新ans,时间复杂度很大,必定超时,而使用单调队列,可以避免一些无谓的步骤。

下面是AC的代码,看注释加上上面的应该就可以理解了.

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

int a[200005], sum[200005];
int main()
{
	int t, N, K, i;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &N, &K);
		int n = N;                                   //备份N
		sum[0] = 0;
		for(i = 1; i <= N; i++)                      //输入
		{
			scanf("%d", &a[i]);
			a[N + i] = a[i];
			sum[i] = sum[i - 1] + a[i];              //求前i项的序列和(1 <= i <= N)
		}
		for(i = N + 1; i <= 2 * N; i++)
			sum[i] = sum[i - 1] + a[i];              //求前i项的序列和(N + 1 <= i <= 2 * N)
		deque<int> que;                              //定义双向队列
		int ans = -10000000;
		int start, end;
		N = N + K - 1;                               //序列长度不超过K,只需要前面的N + K - 1项就足以,
		que.clear();
		for(i = 1; i <= N; i++)                      //单调队列保持为递增的序列。
		{
			while(!que.empty() && sum[i - 1] < sum[que.back()])     //插入的数比队尾的小,删除队尾,再比较,直到比队尾大。
				que.pop_back();                                 //删除的元素的价值比插入的元素的价值小。因为要序列和最大
										//下面的ans要不断的更新,队头的元素要相对最小,使解最优。
			while(!que.empty() && i - que.front() > K)              //队列长度大于K,删除队头。
				que.pop_front();                                //保持长度不大于K,不断的更新ans
			que.push_back(i - 1);                                   //加入队尾
			if(sum[i] - sum[que.front()] > ans)                     //判断序列和是否大于ans,不断更新ans
			{
				ans = sum[i] - sum[que.front()];
				start = que.front() + 1;
				end = i;
			}
		}
		if(end > n)                                  //末尾位置超过n,减掉n。
			end -= n;
		printf("%d %d %d\n", ans, start, end);
	}
	return 0;
}

对于单调队列也是初学,如有错误,欢迎指正,互相学习。~~

时间: 2024-11-05 12:27:19

杭电ACM3415——Max Sum of Max-K-sub-sequence的相关文章

杭电 5053 the Sum of Cube(求区间内的立方和)打表法

Description A range is given, the begin and the end are both integers. You should sum the cube of all the integers in the range. Input The first line of the input is T(1 <= T <= 1000), which stands for the number of test cases you need to solve. Eac

HDU 1003 Max Sum(dp,最大连续子序列和)

Max Sum Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the input

杭电1003-Max Sum

Max Sum Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the input

HDU 1003.Max Sum【最大连续子序列和】【8月14】

Max Sum Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the input

POJ 1003 Max Sum

Max Sum Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the input

杭电 1003 Max Sum

http://acm.hdu.edu.cn/showproblem.php?pid=1003 Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 142781    Accepted Submission(s): 33242 Problem Description Given a sequence a[1],a[2],a[3

杭电1003(Max Sum) 首次dp

点击打开杭电1003 Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the inp

杭电1024(Max Sum Plus Plus)

点击打开杭电1024 Problem Description Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem. Given a consecutive

杭电1003 Max Sum TLE

这一题目是要求连续子序列的最大和,所以在看到题目的一瞬间就想到的是把所有情况列举出来,再两个两个的比较,取最大的(即为更新最大值的意思),这样的思路很简单,但是会超时,时间复杂度为O(n^3),因为有三重for语句 #include<stdio.h> #define maxn 101000 int main() { int ncase,flag=1,n,max,sum=0,h,z,a[maxn]; long i,j,k; scanf("%d",&ncase); wh