1. 程式人生 > >HDU - 3415(DP + 單調隊列)

HDU - 3415(DP + 單調隊列)

show while href double lan 最小 鏈接 %d push

鏈接: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; }

HDU - 3415(DP + 單調隊列)