HDU 3415 Max Sum of Max-K-sub-sequence[单调队列优化dp]

这题是有下界的最大子段和, 无上下界的最大子段和请看

hh大牛把这个归为单纯的单调队列题, 因为这个状态间不用转移, 其实无所谓啦, 思路都是一样的

思路:

单调队列优化dp
以i结尾的最大子段和 d[i] = max{ sum[i]-sum[k] | k=[i-K , i-1] }.
化为 d[i] = max(f[k])+sum[i]. f[k]=-sum[k], k=[i-k, i-1]. k>=0
另外, 题目是环, 把序列处理成2*n就行了.


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "

//	单调队列优化dp
//	以i结尾的最大子段和 d[i] = max{ sum[i]-sum[k] | k=[i-K , i-1] }.
//	化为	d[i] = max(f[k])+sum[i]. f[k]=-sum[k], k=[i-k, i-1]. k>=0
//	另外, 题目是环, 把序列处理成2*n就行了.

#define MAXN 100002*2	//环
int sum[MAXN];

int f[MAXN];
int q[MAXN];
int front, tail;

int main()
{
	int T = Rint();
	while(T--)
	{
		sum[0] = 0;
		int n = Rint();
		int K = Rint();
		FOR(i, 1, n)
		{
			int t = Rint();
			sum[i]=sum[i-1]+t;
			sum[i+n] = sum[i];
		}
		FOR(i, 1+n, n+n)
		{
			sum[i] += sum[n];
		}
		front = tail = 0;
		f[0] = 0;
		int maxd = -INF;
		int st=1, en=1;
		FOR(i, 1, n*2)
		{
			f[i] = -sum[i];
			//	把i-1丢进队列
			while(front<tail && f[q[tail-1]]<f[i-1]) tail--;
			q[tail++] = i-1;

			//	算d[i]
			int low = max(i-K, 0);
			while(q[front]<low) front++;
			int d = f[q[front]]+sum[i];
			if(d>maxd)
			{
				maxd = d;
				st = q[front]+1;	//这里出现的st , 必小于 n
				en = i>n? i-n: i;
			}
		}
		printf("%d %d %d\n", maxd, st, en);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值