题目
解法
无论多么麻烦的代码写完过后都要耐着性子检查。
首先有朴素 (n^2) 的 (mathtt{DP})。
虽然不知道是怎么想到的,但是可以尝试思考一下 (mathtt{cdq}) 分治。考虑在询问 (i) 第一次覆盖区间 ( ext{mid}) 时计算这个询问。即当二分到区间 ([l,r]) 时,我们先 (mathtt{DP}) 这个区间,再通过得到的值算出询问答案。为什么这是正确的?其实也就是为什么 ([l,r]) 一定覆盖这个询问?容易想到如果 ([l,r]) 未覆盖询问 (i),那么 (l,r) 中的一个一定在询问 (i) 的区间范围内,而这个在区间范围内的 (l / r) 一定可以向外扩展,也就是说一定是之前的一个 ( ext{mid}),所以假设不成立。
可是如果我们朴素 (mathtt{DP}) 显然还是过不了的。
发现朴素 (mathtt{DP}) 复杂度那么高是因为要保证选取的数大于等于 (l),小于等于 (r) 这两个条件,如果我们把这两个条件拆开做,再合并起来会怎样呢?看上去十分不可做。
不过这道题我们可以保证 (l_ile ext{mid},r_i> ext{mid})。我们就可以以 ( ext{mid}) 为界分别 (mathtt{DP}) 两类条件。如何合并?显然需要枚举穿过 ( ext{mid}) 的 (L) 条语录,由于这道题 (L) 特别小,所以方法可行。
时间复杂度 (mathcal O(nLlog n))。
但是细节贼多。
代码
#include <cstdio>
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define print(x,y) write(x),putchar(y)
int read() {
int x=0,f=1; char s;
while((s=getchar())>'9' || s<'0') if(s=='-') f=-1;
while(s>='0' && s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
void write(int x) {
if(x<0) return (void)(putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
#include <iostream>
using namespace std;
const int maxn=1e5+5;
int n,L,a[maxn],m,f[55][maxn],g[55][maxn],ans[maxn];
struct node {int l,r,id;} q[maxn],tl[maxn],tr[maxn];
void calcL(int l,int r) {
rep(i,0,min(r-l,L)) { // 枚举中间那 L 条语录在 [l,mid] 中有多少条
f[i][r-i+1]=0;
fep(j,r-i,l)
f[i][j]=max(f[i][j+1],(j+L-1>r-i?0:f[i][j+L]+a[j+L-1]));
}
}
void calcR(int l,int r) {
rep(i,0,min(r-l,L)) {
g[i][l+i-1]=0;
rep(j,l+i,r)
g[i][j]=max(g[i][j-1],(j-L+1<l+i?0:g[i][j-L]+a[j]));
}
}
void dicon(int l,int r,int ql,int qr) {
if(ql>qr || r-l+1<L) return;
int mid=l+r>>1,totl=0,totr=0;
calcL(l,mid),calcR(mid+1,r);
rep(i,ql,qr)
if(q[i].l>mid) tr[++totr]=q[i];
else if(q[i].r<=mid) tl[++totl]=q[i];
else {
if(q[i].l<l || q[i].r>r) puts("fuck bitch!");
ans[q[i].id]=max(f[0][q[i].l]+g[0][q[i].r],0);
rep(j,max(1,L+mid-q[i].r),min(mid-q[i].l+1,L))
ans[q[i].id]=max(ans[q[i].id],f[j][q[i].l]+g[L-j][q[i].r]+a[mid+L-j]);
// mid-j+1>=l -> j<=mid-l+1
// L-j+mid<=r -> j>=L+mid-r
}
rep(i,1,totl) q[ql+i-1]=tl[i];
rep(i,1,totr) q[ql+totl+i-1]=tr[i];
dicon(l,mid,ql,ql+totl-1),dicon(mid+1,r,ql+totl,ql+totl+totr-1);
}
int main() {
n=read(),L=read();
rep(i,1,n) a[i]=a[i-1]+read();
fep(i,n,L) a[i]-=a[i-L];
m=read();
rep(i,1,m) q[i].l=read(),q[i].r=read(),q[i].id=i;
dicon(1,n,1,m);
rep(i,1,m) print(ans[i],'
');
return 0;
}