P3594 [POI2015]WIL-Wilcze doły

\(O(n^3)\)暴力

比较好写

	for(int i = d;i <= n;++i)
		for(int j = 1;j <= i-d+1;++j)
			for(int k = j;k <= i-d+1;++k)
				if(sum[i] - sum[j-1] - (sum[k+d-1]-sum[k-1]) <= p)
					ans = max(ans,i-j+1);

\(O(n^2)\)尺取法优化选择

	for(int i = 1;i <= n;++i){
		s += w[i];
		if(i-l+1 <= d){
			ans = max(ans,i-l+1); continue;
		}
		if(s > p){
			bool flag = false;
			for(int j = l;j <= i-d+1;++j){//寻找可以改变的左端点 
				if(s - (sum[j+d-1]-sum[j-1]) <= p){
					flag = true;
					ans = max(ans,i-l+1);
				}
			}
			if(!flag) s -= w[l++];//弹队头 
		}
	}

显然,被修改长为 \(d\) 的区间内的数和越大越好,于是可以尺取法过程中,单调队列 维护单调递增的 目前尺取的区间内长为 \(d\) 的区间和左端点优化即可

\(O(n)\)

int p,d,w[N],l = 1,ans,q[N]; ll sum[N],s;
int main(){
	n = read(); p = read(); d = read();
	for(re int i = 1;i <= n;++i){
		w[i] = read(),sum[i] = sum[i-1] + w[i];
	}
	for(re int i = 1;i <= d;++i) s += w[i];
	int head = 1,tail = 1;
	q[head] = d;
	for(re int i = d+1;i <= n;++i){
		s += w[i];
		while(head <= tail && sum[i]-sum[i-d] >= sum[q[tail]] - sum[q[tail]-d])
			--tail;
		q[++tail] = i;
		while(head <= tail && q[head]-d+1 < l) ++head;
		while(s - (sum[q[head]]-sum[q[head]-d]) > p) {
			s -= w[l++];
			while(head <= tail && q[head]-d+1 < l) ++head;
		}
		ans = max(ans,i-l+1);
	}
	write(ans);
}

也有\(O(n\log n)\)的二分,也能水过,懒得写了

posted @ 2020-11-15 16:43  INFP  阅读(95)  评论(0编辑  收藏  举报