题面: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);
}