[NC15553] 数学考试
| 12
 3
 
 | 时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 32768K,其他语言65536K
 64bit IO Format: %lld
 
 | 
题目描述
今天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)。
输入描述
| 12
 3
 
 | 第一行一个整数T(T<=10),代表有T组数据接下来一行两个整数n,k,(2<=n<=200,000),(1<=k,2k<=n)
 接下来一行n个整数a1,a2,...,an,(-100,000<=ai<=100,000)
 
 | 
输出描述
输入
| 12
 3
 4
 5
 
 | 26 3
 1 1 1 1 1 1
 8 2
 -1 0 2 -1 -1 2 3 -1
 
 | 
输出
题解
题目解析
这道题是一个区间dp+前缀和的题目,按理说应该挺简单的= =.但是我还是卡了好长时间.
这道题的做法是 $O(n)$ 方法.用一个res1变量始终维护全部左侧长度为k的区间最大值.然后依次一个一个遍历右侧所有长度为k的区间就好了.因为我们已经维护左侧所有长度为k的最大值了,res2就可以维护以移动指针i到i+k区间与i左边所有区间的最大值就好了,然后i从k->n-k遍历一遍就得到答案了.
AC代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | #include <iostream>#include <cmath>
 using namespace std;
 typedef long long ll;
 const int MAXN = 200010;
 
 ll dp[MAXN],sum[MAXN],res1,res2;
 int T,n,k,temp;
 
 signed main(){
 cin >> T;
 while(T--){
 cin >> n >> k;
 res1 = res2 = -1e18;
 for(int i=1;i<=n;i++){
 cin >> temp;
 sum[i] = sum[i-1] + temp;
 }
 for(int i=k;i<=n-k;i++){
 res1 = max(res1,sum[i]-sum[i-k]);
 res2 = max(res2,res1+sum[i+k]-sum[i]);
 }
 cout << res2 << endl;
 }
 return 0;
 }
 
 |