JZOJ 5936. 【NOIP2018模拟10.29】逛公园

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangjingyuan107/article/details/83536079

题目

在这里插入图片描述

解题思路

50分可以直接暴力。
能用一个变量存储的,绝对不允许用数组!!
寻址时间卡爆!!!
# d e f i n e   M i n ( x , y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) \#define\ Min(x,y) ((x)<(y)?(x):(y)) 这一句比调用过程快。
这题在比赛的时候已经猜测到,需要维护一个具有单调性的函数。
比赛的时候,设了 a [ i ] [ j ] a[i][j] 表示从i出发,一直加,知道取了min,最多能够拥有的愉悦值。
显然, a [ i ] [ j ] a[i][j] 具有单调性。
但是维护这个东西没用。
考虑从直接暴走的转移过来。(转移需要"粗暴",找一段最基础的行程,即 a n s = m a x ( x 0 , m i n ( a n s + d [ i ] , l [ i ] ) ) ans=max(x_0,min(ans+d[i],l[i]))
F ( i , j , x 0 ) F(i,j,x_0) 表示初始值为 x 0 x_0 ,从i走到j,最后的愉悦值是多少。
G ( i , j ) = F ( i , j , + ) G(i,j)=F(i,j,+∞) ,则 F ( i , j , x 0 ) = m i n ( G ( i , j ) , S ( i , j ) + x 0 ) F(i,j,x_0)=min(G(i,j),S(i,j)+x_0)
其中, S ( i , j ) S(i,j) 表示 k = i j d [ k ] \sum_{k=i}^j d[k]
显然,要么在一个地方被 l [ k ] l[k] 卡住了,要么没被卡。
注意到,询问的是一个区间 [ l , r ] [l,r] ,即答案为 M a x ( F ( i , j , x 0 ) ) , i [ l , r ] , j [ l , r ] , i j Max(F(i,j,x_0)),i∈[l,r],j∈[l,r],i\leq j
有很多的 F ( i , j , x 0 ) F(i,j,x_0) 是冗余的,寻找一个方法将它们剔除。
有一个结论是正确的,当 G ( l 1 , r 1 ) G ( l 2 , r 2 ) G(l_1,r_1)\geq G(l_2,r_2) S ( l 1 , r 1 ) S ( l 2 , r 2 ) S(l_1,r_1)\geq S(l_2,r_2) ,那么 [ l 2 , r 2 ] [l_2,r_2] 这个区间就不需要被选了。
有2种暴力
①暴力地j++,这样会多了很多个 F ( i , j , x 0 ) F(i,j,x_0) 的状态。在50分DP的时候只会将 [ i , j 1 ] [i,j-1] 中最优的答案来更新j。
②考虑每个询问都暴力地将所有的 F ( i , j , x 0 ) , i [ l , r ] , j [ l , r ] , i j F(i,j,x_0),i∈[l,r],j∈[l,r],i\leq j 加入,根据红体字的结论,没被剔除的状态具有单调性。最后必将有一个 G ( i , j ) G(i,j) 不增, S ( i , j ) S(i,j) 不减的序列。
两种暴力显然都是对的。
那么该怎么结合?
分块。块大小为 n \sqrt{n}
每一块预处理删除不合法的 [ l 2 , r 2 ] [l_2,r_2]
块内的贡献直接二分计算 G ( i , j ) S ( i , j ) G(i,j)-S(i,j) 具有单调性。
跨块的,考虑最终答案,可能是从之前的某一块开始到当前块结束,也有可能是从当前块开始到后面的某一块结束。
维护一个Y值表示前面的块给这一块的贡献。
如何计算从之前的某一块开始到当前块结束?
对于第i块,寻找 F ( l [ i ] , j , Y ) F(l[i],j,Y) 里面的最优的。维护一个前缀 ( l [ i ] , j ) (l[i],j) 的相应函数,踢掉不合法的。
如何计算从当前块开始到后面的某一块结束
从第i块开始有可能比之前的更优。
维护一个后缀 ( j , r [ i ] ) (j,r[i]) 的相应函数,踢掉不合法的。
寻找 F ( j , r [ i ] , x 0 ) F(j,r[i],x_0) 里最优的。
当然,还有一种可能。就是起点在第i块之前,终点在第i块之后。
维护一下,从上个Y走满整块到下个Y的最佳答案即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 40010
#define M 205
#define P(a) putchar(a)
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{int fi,se;};
int d[N],lim[N];
int i,j,k,n,q,sq,cs,cnt;
int sm,tot;
int L,R,x0,stk;
int l[N],r[N],bel[N],sum[N];
int F2[M][M][M];
int sip[M],sis[M],sia[M];
note pr;
note temp[N],st[N];
note pre[M][N],suf[M][N],all[M][N];
int read(){
	int fh=0,rs=0;char ch=0;
	while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
	if(ch=='-')fh=1,ch=getchar();
	while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
	return fh?-rs:rs;
}
void write(int x){
	if(x>9)write(x/10);
	P(x%10+'0');
}
int G(int L,int R){return F2[bel[L]][L-l[bel[L]]][R-l[bel[L]]];}
int ef0(int z,int x0){
	int rs=0,siz=sia[z];
	int L2=1,R2=siz,Mid,w=L2;
	while(L2<=R2){
		Mid=(L2+R2)>>1;
		if(all[z][Mid].fi-all[z][Mid].se<=x0)w=Mid,L2=Mid+1;
		else R2=Mid-1;
	}
	rs=Min(all[z][w].fi,all[z][w].se+x0);
	if(w<siz)rs=Max(rs,Min(all[z][w+1].fi,all[z][w+1].se+x0));
	return rs;
}
int ef1(int z,int x0){
	int rs=0,siz=sip[z];
	int L2=1,R2=siz,Mid,w=L2;
	while(L2<=R2){
		Mid=(L2+R2)>>1;
		if(pre[z][Mid].fi-pre[z][Mid].se<=x0)w=Mid,L2=Mid+1;
		else R2=Mid-1;
	}
	rs=Min(pre[z][w].fi,pre[z][w].se+x0);
	if(w<siz)rs=Max(rs,Min(pre[z][w+1].fi,pre[z][w+1].se+x0));
	return rs;
}
int ef2(int z,int x0){
	int rs=0,siz=sis[z];
	int L2=1,R2=siz,Mid,w=L2;
	while(L2<=R2){
		Mid=(L2+R2)>>1;
		if(suf[z][Mid].fi-suf[z][Mid].se<=x0)w=Mid,L2=Mid+1;
		else R2=Mid-1;
	}
	rs=Min(suf[z][w].fi,suf[z][w].se+x0);
	if(w<siz)rs=Max(rs,Min(suf[z][w+1].fi,suf[z][w+1].se+x0));
	return rs;
}
int F(int L,int R,int x0){
	int res=0,i,Y;
	if(bel[L]==bel[R]){
		Y=x0;
		fo(i,L,R){
			Y=Max(x0,Min(Y+d[i],lim[i]));
			res=Max(res,Y);
		}
		return res;
	}
	Y=x0;
	fo(i,L,r[bel[L]]){
		Y=Max(x0,Min(Y+d[i],lim[i]));
		res=Max(res,Y);
	}
	Y=Max(Y,x0);
	fo(i,bel[L]+1,bel[R]-1){
		res=Max(res,ef1(i,Y));
		res=Max(res,ef0(i,x0));
		Y=Max(Min(Y+sum[i],G(l[i],r[i])),ef2(i,x0));
		Y=Max(Y,x0);
		res=Max(res,Y);
	}
	fo(i,l[bel[R]],R){
		Y=Max(x0,Min(Y+d[i],lim[i]));
		res=Max(res,Y);
	}
	return res;
}
bool cmp(note a,note b){
	return a.fi<b.fi||(a.fi==b.fi&&a.se<b.se);
}
void chuli(int z,int X){
	sort(temp+1,temp+tot+1,cmp);
	int i;
	stk=0;
	st[++stk]=temp[i];
	fo(i,2,tot){
		while(stk&&temp[i].se>=st[stk].se)stk--;
		st[++stk]=temp[i];
	}
	if(z==0){fo(i,1,stk)all[X][i]=st[i];sia[X]=stk;}else
	if(z==1){fo(i,1,stk)pre[X][i]=st[i];sip[X]=stk;}else
	{fo(i,1,stk)suf[X][i]=st[i];sis[X]=stk;}
}
void yuchuli(int x){
	int i,x0;
	fo(i,l[x],r[x]){
		x0=2139062143;
		fo(j,i,r[x]){
			x0=Min(x0+d[j],lim[j]);
			F2[x][i-l[x]][j-l[x]]=x0;
		}
	}
	//全部
	tot=0;
	fo(i,l[x],r[x]){
		sm=0;
		fo(j,i,r[x]){
			sm=sm+d[j];
			temp[++tot]=(note){G(i,j),sm};
		}
	}
	chuli(0,x);
	//左
	tot=0;sm=0;
	fo(i,l[x],r[x]){
		sm=sm+d[i];
		temp[++tot]=(note){G(l[x],i),sm};
	}
	chuli(1,x);
	//右
	tot=0;sm=0;
	fd(i,r[x],l[x]){
		sm=sm+d[i];
		temp[++tot]=(note){G(i,r[x]),sm};
	}
	chuli(2,x);
}
int main(){
	n=read(),q=read();
	fo(i,1,n)d[i]=read();
	fo(i,1,n)lim[i]=read();
	sq=sqrt(n);
	fo(i,1,n){
		bel[i]=(i-1)/sq+1;
		if(!l[bel[i]])l[bel[i]]=i;
		r[bel[i]]=i;
		sum[bel[i]]+=d[i];
	}
	cnt=bel[n];
	fo(i,1,cnt)yuchuli(i);
	fo(cs,1,q){
		L=read(),R=read(),x0=read();
		write(F(L,R,x0)),P('\n');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangjingyuan107/article/details/83536079