题面:https://codeforces.com/problemset/problem/407/E

 

 

题解

这道题坑了我3个小时

都是因为网上有一个set做法

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
#define N 200005
#define LL long long
const LL INF=0x3f3f3f3f3f3fll;
LL a[N];
set<LL> S;
set<LL>::iterator i1,i2;
int main()
{
	int n,k,d,i,j,al=1,ar=1;
	scanf("%d%d%d",&n,&k,&d);
	for(i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		a[i]+=1ll*INF;
	}
	if(d==0){
		for(i=1;i<=n;i=j){
			for(j=i;j<=n;j++)
				if(a[i]!=a[j])break;
			if(ar-al<j-i) al=i,ar=j-1;
		}
	}
	else{
		for(i=1,j=0;i<=n;i++){
			if(j-i>ar-al){
				i1=S.begin();i2=S.end();i2--;
				if((*i2)-(*i1)<=j-i+k)
					al=i,ar=j;
			}
			for(j++;j<=n;j++){
				if(a[i]%d!=a[j]%d||S.count(a[j]/d))break;
				S.insert(a[j]/d);
				if(j-i>ar-al){
					i1=S.begin();i2=S.end();i2--;
					if((*i2)-(*i1)<=j-i+k)
						al=i,ar=j;
				}
			}
			if(i<=j)S.erase(a[i]/d);
			else j=i;
			j--;
		}
	}
	printf("%d %d",al,ar);
}

这左右端点显然没有单调性啊,有可能把右端点直接移动到真正可以更新的答案的后面,就会跳过正确答案了

4 1 1

-3 1 3 7

这个程序会删除1 1

正确答案是2 3

还是自己太菜了,看了半天也没看出问题

感谢Freopen大佬把我救了出来并给了我数据

 

回归正题

这道题我们枚举右端点,用线段树维护每个左端点的花费

发现这个花费就是max(l,r)/d-min(l,r)/d+l-r

要让这个花费小于等于k

也就是说让max(l,r)/d-min(l,r)/d+l<=k+r

维护后缀的min,max用单调栈+线段树就可以了,至于l就在build的时候加进权值即可

 

这道题还有一个加强版:https://blog.csdn.net/c20181220_xiang_m_y/article/details/105908002详见Master.Yi大佬的博客

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 200005
#define LL long long
#define lc i<<1
#define rc i<<1|1
const int INF=1000000000;
LL val[N];map<LL,int> last;
struct node{
	int l,r;
	LL la,x;
}a[N<<2];
int sl[N],topl,sr[N],topr;
void cal(int i,LL k){a[i].la+=k;a[i].x+=k;}
void pushdown(int i)
{
	if(a[i].la&&a[i].l<a[i].r){
		cal(lc,a[i].la);cal(rc,a[i].la);
		a[i].la=0;
	}
}
void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	if(l==r){a[i].x=l;return;}
	int mid=(l+r)>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	a[i].x=min(a[lc].x,a[rc].x);
}
void insert(int i,int l,int r,LL k)
{
	if(a[i].l>r||a[i].r<l)return;
	pushdown(i);
	if(l<=a[i].l&&a[i].r<=r){cal(i,k);return;}
	insert(lc,l,r,k);insert(rc,l,r,k);
	a[i].x=min(a[lc].x,a[rc].x);
}
bool flg;int ans;
int EF(int i,int k)
{
	if(a[i].l==a[i].r)return a[i].l;
	pushdown(i);
	if(a[lc].x<=k)return EF(lc,k);
	else return EF(rc,k);
}
void query(int i,int l,int r,int k)
{
	if(a[i].l>r||a[i].r<l)return;
	pushdown(i);
	if(l<=a[i].l&&a[i].r<=r){
		if(a[i].x<=k)
			flg=1,ans=EF(i,k);
		return;
	}
	if(!flg)query(lc,l,r,k);
	if(!flg)query(rc,l,r,k);
}
void del(int i,int x)
{
	if(x<a[i].l||x>a[i].r)return;
	pushdown(i);
	if(a[i].l==x&&a[i].r==x){a[i].x=0;return;}
	del(lc,x);del(rc,x);
	a[i].x=min(a[lc].x,a[rc].x);
}
void print(int i)
{
	if(a[i].l==a[i].r){printf("%lld ",a[i].x);return;}
	pushdown(i);
	print(lc);print(rc);
}
int main()
{
	int n,k,d,i,L,al=1,ar=1;
	n=gi();k=gi();d=gi();
	for(i=1;i<=n;i++)val[i]=gi()+1ll*INF;
	if(d==0){
		for(i=L=1;i<=n;i++){
			while(L<=n&&val[L]!=val[i])L++;
			if(ar-al<i-L)al=L,ar=i;
		}
		printf("%d %d",al,ar);
		return 0;
	}
	build(1,1,n);
	for(i=L=1;i<=n;i++){
		int tmp=L;
		if(val[i]%d==val[i-1]%d)
			L=max(L,last[val[i]]+1);
		else L=i;
		last[val[i]]=i;
		while(tmp<L)del(1,tmp++);
		while(topl&&sl[topl]>=L&&val[sl[topl]]>=val[i]){
			insert(1,max(L,sl[topl-1]+1),sl[topl],val[sl[topl]]/d);
			topl--;
		}
		insert(1,max(L,sl[topl]+1),i,-val[i]/d);
		sl[++topl]=i;
		while(topr&&sr[topr]>=L&&val[sr[topr]]<=val[i]){
			insert(1,max(L,sr[topr-1]+1),sr[topr],-val[sr[topr]]/d);
			topr--;
		}
		insert(1,max(L,sr[topr]+1),i,val[i]/d);
		sr[++topr]=i;
		flg=0;ans=0;
		query(1,L,i,k+i);
		if(ar-al<i-ans)al=ans,ar=i;
		//printf("%d %d\n",L,i);
		//print(1);printf("\n");
	}
	printf("%d %d",al,ar);
}