HDU - 3415(DP + 单调队列)

链接:HDU - 3415

题意:给出一个包含 n 个数的环,求满足长度大于 0 小于等于 k 的最大区间和。

题解:将数组加倍,形成环。求一个前缀和sum。枚举每一个sum[i],以 i 结尾的最大值就是 sum[i] - min(sum[i - k],……,sum[i - 1]),这个最小值用单调队列维护。

#include <bits/stdc++.h>
using namespace std;

const double EPS = 1e-6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
int n, k, l, r;
int a[maxn];
long long sum[maxn];
list<int> Q;

long long Cal(int a[], int n, int k)
{
    for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i - 1];

    Q.clear();
    Q.push_back(0);

    int ans = -INF;
    for(int i = 1; i <= n; i++){
        while(!Q.empty() && i - Q.front() > k) Q.pop_front();
        int j = i - 1;
        if(!Q.empty()) j = Q.front();

        if(ans < sum[i] - sum[j]){
            ans = sum[i] - sum[j];
            l = j % (n >> 1) + 1;
            r = (i - 1) % (n >> 1) + 1;
        }

        while(!Q.empty() && sum[Q.back()] > sum[i]) Q.pop_back();
        Q.push_back(i);
    }

    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &k);
        for(int i = 0; i < n; i++){
            scanf("%d", &a[i]);
            a[i + n] = a[i];
        }

        long long ans = Cal(a, n << 1, k);

        printf("%lld %d %d\n", ans, l, r);
    }

    return 0;
}

 

posted @ 2018-08-26 16:51  鬼沐冢  阅读(307)  评论(0编辑  收藏  举报