开始比较天真,写了个枚举两个区间的算法时间复杂度o(n^2)果断超时了。然后就想用rmq但rmq的时间复杂度o(n*logn)担心也会超时。于是就想用dp做了。回想了各种dp题。以前求连续区间和都只是一个区间没处理两个区间的。无奈为了不让rating掉的太惨只能硬着头皮上了。写了下最优解的结构
ans=MAX(sum[i]-sum[i-k]+sum[j]-sum[j-k])。i<j。sum[i]代表前i项和。i和j是区间的右端点。
答案要求左端点。左端点用右端点-k+1就行了。所以是一样的。
ans=MAX(sum[i]-sum[i-k])+sum[j]-sum[j-k]。
所以我们枚举j。即右区间的右端点就行了。再用状态转移辅助量q[i]表示
前1到i个元素连续k个元素的最大值。那么
ans=q[j-k]+sum[j]-sum[j-k]。
q[i]=MAX(q[i-1],sum[i]-sum[i-k])。
时间复杂度瞬间就降到o(n)了。
问题就迎刃而解了。。。。。。。
代码如下:
#include <iostream>
#include<stdio.h>
#include<string.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
using namespace std;
__int64 sum[200100],ma;
struct node
{
__int64 maxx;//记录值
int id;//记录下标
} q[200100];
int main()
{
int n,k,i,p1,p2;
sum[0]=0;
while(~scanf("%d%d",&n,&k))
{
ma=-1;
memset(q,0,sizeof q);
for(i=1; i<=n; i++)
{
scanf("%I64d",&sum[i]);
sum[i]+=sum[i-1];
}
for(i=k; i<=n; i++)//由于是从大到小枚举的所以a,b都是最小的
{
if(sum[i]-sum[i-k]>q[i-1].maxx)//更新q[i]
{
q[i].maxx=sum[i]-sum[i-k];
q[i].id=i;
}
else
{
q[i].maxx=q[i-1].maxx;
q[i].id=q[i-1].id;
}
if(sum[i]-sum[i-k]+q[i-k].maxx>ma)
{
ma=sum[i]-sum[i-k]+q[i-k].maxx;
p1=q[i-k].id-k+1;//左起点
p2=i-k+1;//右起点
}
}
printf("%d %d\n",p1,p2);
}
return 0;
}