1. 程式人生 > >清北學堂模擬賽d2t4 最大值(max)

清北學堂模擬賽d2t4 最大值(max)

固定 bsp 輸出格式 include its style 有趣 using -1

題目描述
LYK有一本書,上面有很多有趣的OI問題。今天LYK看到了這麽一道題目:
這裏有一個長度為n的正整數數列ai(下標為1~n)。並且有一個參數k。
你需要找兩個正整數x,y,使得x+k<=y,並且y+k-1<=n。並且要求a[x]+a[x+1]+…+a[x+k-1]+a[y]+a[y+1]+…+a[y+k-1]最大。
LYK並不會做,於是它把題扔給了你。

輸入格式(max.in)
第一行兩個數n,k。
第二行n個數,表示ai。

輸出格式(max.out)
兩個數表示x,y。若有很多種滿足要求的答案,輸出x最小的值,若x最小仍然還有很多種滿足要求的答案,輸出y最小的值。

輸入樣例
5 2
6 1 1 6 2

輸出樣例
1 4

對於30%的數據n<=100。
對於60%的數據n<=1000
對於100%的數據1<=n<=100000,1<=k<=n/2,1<=ai<=10^9。

分析:一個O(n^3)的做法,直接枚舉兩個區間,再枚舉求區間和.因為用到了區間和,所以可以用前綴和優化到O(n^2).然後可以發現這個區間長度是固定的,我們可以在挪動右端點的時候右邊每加一個數,左邊彈一個數,用O(n)的時間處理出每一段長度為k的區間的和,在處理的過程中可以順便記錄j-k之前的區間最大值,一邊求和一邊統計答案就可以了.

#include <bits/stdc++.h>

using namespace
std; int n,k,lastt = 1,x,y; long long a[100010],r[100010],Max,sum,ans; int main() { freopen("max.in","r",stdin); freopen("max.out","w",stdout); scanf("%d%d",&n,&k); for (int i = 1; i <= n; i++) scanf("%lld",&a[i]); for (int i = 1; i <= n; i++) { sum
+= a[i]; if (i - k > 0) sum -= a[i - k]; r[i] = sum; if (i - k > 0) { if (Max < r[i - k]) { Max = max(Max,r[i - k]); lastt = i - k; } } if (Max + r[i] > ans) { ans = max(ans,Max + r[i]); x = max(1,lastt - k + 1); y = max(1,i - k + 1); } } printf("%d %d\n",x,y); return 0; }

清北學堂模擬賽d2t4 最大值(max)