BZOJ

题目

传送门

解法

无论多么麻烦的代码写完过后都要耐着性子检查。

首先有朴素 (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;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/14483515.html