zoukankan      html  css  js  c++  java
  • [JZOJ4665] 【GDOI2017模拟7.21】数列

    题目

    题目大意

    给你一个数列,让你找到一个最长的连续子序列,满足在添加了至多KK个数之后,能够变成一条公差为DD的等差数列。


    思考历程

    一眼看上去似乎是一道神题……
    没有怎么花时间思考,毕竟时间都砸到T1和T2上了。


    正解

    仔细推一下就会发现这种等差数列[j,i][j,i]有三个简单的条件:

    1. 所有数模dd的余数相同
    2. 没有重复的数(d=0d=0的时候除外)
    3. max(j,i)min(j,i)d+1ij+1+kfrac{max(j,i)-min(j,i)}{d}+1leq i-j+1+k

    前面两个都能很快地预处理。
    现在我们枚举一个右边界rr,前面两个条件可以使我们得知最远的左边界LL
    我们把第三个条件的式子乱搞一下:max(l,r)min(l,r)(rl)dkdmax(l,r)-min(l,r)-(r-l)dleq kd
    考虑一下能不能维护左边的式子。最重要的是维护最小值和最大值。
    随便想想就可以知道,左边界ll在区间[L,r][L,r]中,最小值的取值是一段一段的(最大值也一样)。
    或许能够用这条性质来维护。
    接着就可以想到单调队列。对于最小值和最大值分别维护一条单调队列。
    设单调队列上某个位置的值是xx,上一个位置是yy,那么区间[y+1,x][y+1,x]中的值为a[x]a[x]
    于是我们可以在线段树上区间修改。
    在维护单调队列的过程中,最小(大)值会有些变化。这也可以直接在线段树上改。
    至于(rl)d-(r-l)d,这个是很容易维护的,每次直接将区间[1,r1][1,r-1]dd就可以了。
    询问的时候就是寻找线段树上最左边的小于kdkd的值。这个可以维护最小值,在线段树上二分就可以维护了。


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #define N 200010
    #define INF 1000000000000000000
    int n;
    long long K,D;
    int a[N];
    bool bz[N];
    map<int,int> last;
    int fr[N];
    int q1[N],q2[N];//min max
    int h1,t1,h2,t2;
    long long t[N*4],lazy[N*4];
    inline void pushdown(int k){
    	t[k<<1]+=lazy[k],t[k<<1|1]+=lazy[k];
    	lazy[k<<1]+=lazy[k],lazy[k<<1|1]+=lazy[k];
    	lazy[k]=0;
    }
    void build(int k,int l,int r){
    	t[k]=INF;
    	if (l==r)
    		return;
    	int mid=l+r>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    }
    void add(int k,int l,int r,int st,int en,long long c){
    	if (st<=l && r<=en){
    		t[k]+=c;
    		lazy[k]+=c;
    		return;
    	}
    	pushdown(k);
    	int mid=l+r>>1;
    	if (st<=mid)
    		add(k<<1,l,mid,st,en,c);
    	if (mid<en)
    		add(k<<1|1,mid+1,r,st,en,c);
    	t[k]=min(t[k<<1],t[k<<1|1]);
    }
    void change0(int k,int l,int r,int x){
    	if (l==r){
    		t[k]=0;
    		return;
    	}
    	pushdown(k);
    	int mid=l+r>>1;
    	if (x<=mid)
    		change0(k<<1,l,mid,x);
    	else
    		change0(k<<1|1,mid+1,r,x);
    	t[k]=min(t[k<<1],t[k<<1|1]);
    }
    int query(int k,int l,int r,int en){
    	if (t[k]>K*D)
    		return 0;
    	if (l==r)
    		return l;
    	pushdown(k);
    	int mid=l+r>>1,res=0;
    	res=query(k<<1,l,mid,en);
    	if (!res && mid<en)
    		res=query(k<<1|1,mid+1,r,en);
    	return res;
    }
    int main(){
    	scanf("%d%lld%lld",&n,&K,&D);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&a[i]);
    	if (D==0){
    		int ansl=1,len=1;
    		for (int i=1,j=0;i<=n;++i)
    			if (a[i]!=a[i-1]){
    				if (i-j>len)
    					len=i-j,ansl=j;
    				else if (i-j==len)
    					ansl=j;
    			}
    		printf("%d %d
    ",ansl,ansl+len-1);
    		return 0;
    	}
    	for (int i=1;i<=n;++i)
    		if (i==1 || (a[i]%D+D)%D!=(a[i-1]%D+D)%D)
    			bz[i]=1;
    	for (int i=1;i<=n;++i){
    		fr[i]=last[a[i]];
    		last[a[i]]=i;	
    	}
    	build(1,1,n);
    	h1=h2=1,t1=t2=0;
    	int ansl=1,len=1;
    	for (int i=1,st=1;i<=n;++i){
    		if (bz[i]){
    			h1=h2=1,t1=t2=0;
    			if (st<=i-1)
    				add(1,1,n,st,i-1,INF);
    			st=i;
    		}
    		else if (st<=fr[i]){
    			add(1,1,n,st,fr[i],INF);
    			st=fr[i]+1;
    		}
    		while (h1<=t1 && q1[h1]<st)
    			h1++;
    		while (h2<=t2 && q2[h2]<st)
    			h2++;
    		while (h1<=t1 && a[q1[t1]]>=a[i]){
    			add(1,1,n,q1[t1-1]+1,q1[t1],+a[q1[t1]]-a[i]);
    			t1--;
    		}
    		while (h2<=t2 && a[q2[t2]]<=a[i]){
    			add(1,1,n,q2[t2-1]+1,q2[t2],-a[q2[t2]]+a[i]);
    			t2--;
    		}
    		q1[++t1]=q2[++t2]=i;
    		if (st<=i-1)
    			add(1,1,n,st,i-1,-D);
    		change0(1,1,n,i);
    		int l=query(1,1,n,i);
    		if (i-l+1>len)
    			len=i-l+1,ansl=l;
    		else if (i-l+1==len && l<ansl)
    			ansl=l;
    	}
    	printf("%d %d
    ",ansl,ansl+len-1);
    	return 0;
    }
    

    总结

    单调队列可以干的东西,可不仅仅是DP啊……

  • 相关阅读:
    简单聚合查询
    简单搜索入门
    简单的document操作
    快速检测集群的健康状况
    Log4j和Slf4j的比较
    javascript中escape()、unescape()、encodeURI()、encodeURIComponent()、decodeURI()、decodeURIComponent()比较
    Spring-data-jpa详解,全方位介绍。
    JSON关联属性转换异常
    原生类型 和 参数化类型
    Spring Data JPA
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145212.html
Copyright © 2011-2022 走看看