题号 NC15553
名称 数学考试
来源 2018年长沙理工大学第十三届程序设计竞赛
链接:https://ac.nowcoder.com/acm/problem/15553
来源:牛客网
试题传送门
时间限制: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)。

输入描述:

第一行一个整数T(T<=10),代表有T组数据 接下来一行两个整数n,k,(1<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,…,an,(-100,000<=ai<=100,000)

输出描述:

输出一个整数,qwb能获得的最大分数

示例1
输入

2
6 3
1 1 1 1 1 1
8 2
-1 0 2 -1 -1 2 3 -1

输出

6
7

题解:
题意就是求不想交的前缀与后缀和的最大值
第一反应是线段树(毕竟是有关区间查询 ) ,不过仔细想想也不能这么麻烦(打线段树不累吗? ) ,不过也有大佬用线段树做的。
根据题意知道前缀与后缀长度一样,依据朴素的原则单纯打暴力肯定不行,需要优化优化,怎么优化呢?

我们先求出所有前缀和q[]
然后按照给定前后缀的长度k,求出每个k长区间的和
比如 -1 0 2 -1 -1 2 3 -1 k=2;
每个k长区间的和为:w[]-1 2 1 -2 1 5 2
我们所要求的最大值max=dp1+dp2
dp1是前缀和最大值
dp2是后缀和最大值
那其实就是在w中取一个dp1再取一个dp2,使他们和最大
但注意前缀与后缀不能相交和相连
方法一:
稍微处理下,可以先选后缀,然后前缀的范围就是去除已选的后缀,在里面取最大的前缀
maxx=(q[i]-q[i-k])+max(q[1],q[2],q[3]…q[i-k-1])
(q[i]-q[i-k])后缀和
max(q[1],q[2],q[3]…q[i-k-1])最大的前缀
然后求出maxx的最大值情况
诶,这不就是线性dp吗!wok做完才注意到
方法二:
求出前缀和所能取到的最大值(从头开始),放入数组w1
求出后缀和所能取到的最大值(从尾开始),放入w2中
然后再一个循环,求出w1[i]与w2[i+1](即当前位i的前缀和与排在i之后的最大后缀和之和)的最大值
代码一

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
typedef long long ll;
using namespace std;
const int inf=2e5+4;
ll a[inf];
ll q[inf];
ll w[inf];
ll w1[inf],w2[inf];
int main()
{
   
  int t;
  cin>>t;
  int n,k;
  ll cnt;
  while(t--)
  {
   
	  	cin>>n>>k;
	  	for(int i=1;i<=n;i++)
	  	{
   
	  		cin>>cnt;
	  		q[i]=q[i-1]+cnt; 
		}
		memset(w1,-128,sizeof(w1));
			memset(w2,-128,sizeof(w2));
		cnt=-1e10;
		for(int i=k;i<=n;i++)
	  	{
   
	  		w[i]=q[i]-q[i-k];
		} 
		
		for(int i=k;i<=n;i++)
		{
   
				w1[i]=w[i]>w1[i-1]?w[i]:w1[i-1];
				if(i>=k)
				{
   
					if(w[i]+w1[i-k]>cnt)cnt=w[i]+w1[i-k];
				}
		}
		


		cout<<cnt<<endl;
  }
  return 0;
}

代码二

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
typedef long long ll;
using namespace std;
const int inf=2e5+4;
ll a[inf];
ll q[inf];
ll w[inf];
ll w1[inf],w2[inf];
int main()
{
   
  int t;
  cin>>t;
  int n,k;
  ll cnt;
  while(t--)
  {
   
	  	cin>>n>>k;
	  	for(int i=1;i<=n;i++)
	  	{
   
	  		cin>>cnt;
	  		q[i]=q[i-1]+cnt; 
		}
		memset(w1,-128,sizeof(w1));
			memset(w2,-128,sizeof(w2));
		cnt=-1e10;
		for(int i=k;i<=n;i++)
	  	{
   
	  		w[i]=q[i]-q[i-k];
		} 
		
		for(int i=k;i<=n-k+1;i++)
			w1[i]=w[i]>w1[i-1]?w[i]:w1[i-1];

		
		for(int i=n-k+1;i>=k+1;i--)
			w2[i]=w2[i+1]>w[i+k-1]?w2[i+1]:w[i+k-1];
	
		for(int i=k;i<=n-k+1;i++)
		{
   
			if(w2[i+1]+w1[i]>cnt)cnt=w2[i+1]+w1[i];
		}
		cout<<cnt<<endl;
  }
  return 0;
}

对了还有变形的问题:
(等晚上有空再想吧)