简单的?数学考试
数学考试
https://ac.nowcoder.com/acm/problem/15553
题目大意
今天qwb要参加一个数学考试,这套试卷一共有n道题,每道题qwb能获得的分数为ai,qwb并不打算把这些题全做完, 他想选总共2k道题来做,并且期望他能获得的分数尽可能的大,他准备选2个不连续的长度为k的区间, 即[L,L+1,L+2,....,L+k-1],[R,R+1,R+2,...,R+k-1](R >= L+k)。
分析与题解
很显然,这题是一个贪心的做法,如果我们从1-n枚举第一段的起点,设起点为s,那么只要找到以[s+k,n-k+1](s+k>=n-k+1)中某个点为起点的最大连续k个的和。其中可以通过维护每个点开始的k个数的和以及后缀的k个数的和的最大值即可。
显然转移便是: ma[i] = max(s[i], ma[i+1])
其中ma维护的就是i这个点以及该点以后的连续k段的和的最大值,s[i]是以i为起点的连续k个数的和。
答案便可以通过 ans = max(ans, s[i] + ma[i+k])
更新得到。
代码
#include <bits/stdc++.h> #define LL long long #define rep(i,a,b) for(int i = a; i <= b; i ++) using namespace std; const int N = 2e5 + 50; LL w[N], s[N], ma[N]; int T, n, k; int main() { cin >> T; while(T --) { cin >> n >> k; rep(i, 1, n) { cin >> w[i]; s[i] = 0; } memset(ma, -0x3f3f3f, sizeof ma); LL pre = 0, idx = 0; rep(i, 1, n) { pre += w[i]; if(i == k) s[ ++ idx] = pre; else if(i > k) s[++ idx] = s[idx - 1] + w[i] - w[idx - 1]; } ma[n - k + 1] = s[n - k + 1]; for(int i = n - k ; i >= 1; i --) { ma[i] = max(s[i], ma[i + 1]); } LL res = s[1] + ma[1 + k]; for (int i = 2; i <= n - 2 * k + 1; i ++) { res = max(s[i] + ma[i + k], res); } cout << res << endl; } }