题解 P2698 【[USACO12MAR]花盆Flowerpot】
思路
二分答案套单调队列
此处的单调队列其实就是将求区间和最值的单调队列加上一个绝对值
关于单调队列
先贴代码
memset(Q,0,sizeof(Q));//数组模拟双端队列
int ans=0;
Q[1]=1;
head=1;
tail=1;
for(int i=2;i<=n;i++)
{
while(head<=tail&&water[Q[head]].x<water[i].x-x)
{
head++;
}
if(head<=tail)
ans=max(ans,water[i].y-water[Q[head]].y);//加绝对值
while(head<=tail&&water[Q[tail]].y-water[i].y>=0)
{
tail--;
}
Q[++tail]=i;
}
return ans>=d;
上面是求某数列小于某长度的区间最大和的板子,water[i].y可以预处理成i的前缀和
该问题可简化成选两个距离不超过限制的点使其前缀和相减的值最大
第一个while:区间右移,将与当前当前点差距大于限制的点淘汰出队
第二个while:区间左移,将效果不如当前点的新入队的点淘汰出队
The End?
Code
#include<bits/stdc++.h>
using namespace std;
int l,r,mid,n,t,d,minn=100000000,maxx;
deque<int>q;//STL双端队列,此题我用数组模拟
int Q[100010],head=1,tail=1;
struct node
{
int x,y;
}water[100010];
int cmp(node a,node b)
{
if(a.x!=b.x)
{
return a.x<b.x;
}
return a.y<b.y;
}
int check(int x)
{
memset(Q,0,sizeof(Q));//数组模拟双端队列
int ans=0;
Q[1]=1;
head=1;
tail=1;
for(int i=2;i<=n;i++)
{
while(head<=tail&&water[Q[head]].x<water[i].x-x)
{
head++;
}
if(head<=tail)
ans=max(ans,abs(water[i].y-water[Q[head]].y));//加绝对值
while(head<=tail&&water[Q[tail]].y-water[i].y>=0)
{
tail--;
}
Q[++tail]=i;
}
return ans>=d;
}
int main()
{
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&water[i].x,&water[i].y);
}
for(int i=1;i<=n;i++)
{
minn=min(water[i].y,minn);
maxx=max(water[i].y,maxx);
}
if(maxx-minn<d)//特判无解
{
cout<<-1;
return 0;
}
sort(water+1,water+n+1,cmp);
r=water[n].x;//l==0,此处设定边界
while(l<=r)
{
mid=(l+r)/2;
if(check(mid))
{
r=mid-1;
}
else
{
l=mid+1;
}
}
cout<<l;
}