HDU - 3415 Max Sum of Max-K-sub-sequence : 单调队列

题目点此跳转

思路

 题目意思是给你一全环形的数组(头尾相接), 求所有长度不大于k的区间中 元素和 最大 的的区间 及 最大的元素和。

 区间的和可以使用前缀和相减求出,设sum[i]为从0到i的前缀和, 区间[i, j]的和即为sum[j] - sum[i-1]; 那么对于每一个区间尾j,我们只要求出它前面i个内最小的sum[i]即可,显然单调队列是可以解决的。
 每次区间尾j右移时,将j所在元素入队(注意删除队列中比它大的), 然后将不在此区间内的队首元素出队,剩下的队首元素即为此区间内的最小值。
 注意此题的数组是环形的,多解时输出的顺序也有要求,所以区间尾j的初始值要处理好。

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
#define OT freopen("ot.txt", "w", stdout);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e6 + 100;
const LL INF = 0x7fffffff;
const int dir[5][2] = {0,0,-1,0,1,0,0,-1,0,1};
const int MOD = 1e9 + 7;
const double eps = 1e-6;

int n, k, a[maxn], sum[maxn], ans, L, R;
int q[maxn], p[maxn], ft, rr;

int main() {
    #ifdef _LOCAL
    IN; //OT;
    #endif // _LOCAL

    int t; cin >> t;
    while(t--) {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for(int i = 1; i < k; ++i) a[n+i] = a[i];
        sum[0] = a[n];
        for(int i = 1; i < n+k; ++i) sum[i] = sum[i-1] + a[i];
        ft = rr = 0; ans = -INF;
        q[rr++] = sum[0]; p[rr-1] = 0;
        for(int i = 1; i <= k-1; ++i) {
            while(rr > ft && q[rr-1] >= sum[i]) --rr;
            q[rr++] = sum[i], p[rr-1] = i;
        }
        if(ans < sum[k]-q[ft]) { ans = sum[k]-q[ft]; L = p[ft]%n+1; R =  (k-1)%n+1; }
        for(int i = k+1; i < n+k; ++i) {
            while(rr > ft && q[rr-1] >= sum[i-1]) --rr;
            q[rr++] = sum[i-1], p[rr-1] = i-1;
            if(p[ft] < i-k) ++ft;
            if(ans < sum[i] - q[ft]) { ans = sum[i]-q[ft]; L = p[ft]%n+1; R = (i-1)%n+1; }
            else if(ans == sum[i] - q[ft]) {
                if(L > p[ft]%n + 1) L = p[ft]%n+1, R = (i-1)%n+1;
                else if( L == p[ft]%n + 1 && R-L > (i-1)%n-p[ft]%n) L = p[ft]%n+1, R = (i-1)%n+1;
            }
        }
        printf("%d %d %d\n", ans, L, R);

    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值