题解 P2390 【地标访问】
枚举左点二分右点。。。
check函数判断
然而所谓的4种情况只要变形成伪两种即可
方法是把数轴倒过来
for(int i=1;i<=n;i++)
{
num[i]*=-1;
}
sort(num+1,num+n+1);
很容易地发现正负半轴其实没什么区别
上代码,带一点注释
#include<bits/stdc++.h>
using namespace std;
long long t,n,num[50010],st,l,r,mid,maxx;
int check(long long x,long long y)//左和右
{
long long tot=abs(num[y]);
if(tot<=t&&tot*2>=t)
{
if(y-st+1>maxx)
{
maxx=y-st+1;
return 1;
}
else
{
return 1;
}
}
else
{
if(tot*2<t)
{
if(tot+abs(num[x]-num[y])<=t)
{
if(y-x+1>maxx)
{
maxx=y-x+1;
return 1;
}
else
{
return 1;
}
}
else
{
return 0;
}
}
else
{
if(tot>t)
{
return 0;
}
}
}
}
int main()
{
scanf("%lld%lld",&t,&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
}
sort(num+1,num+n+1);
for(int i=1;i<=n;i++)
{
if(num[i]>=0)
{
st=i;//st是start,即第一个正数
break;
}
}
for(int i=1;i<=st;i++)//st为零时直接跳过,倒转再求一次,显然此时必不为零
{
l=i;//避免check内乱套,l从i开始
r=n;
for(;l<=r;)
{
mid=(l+r)/2;
if(check(i,mid))
{
l=mid+1;
}
else
{
r=mid-1;
}
}
check(i,r);
}
for(int i=1;i<=n;i++)
{
num[i]*=-1;
}
sort(num+1,num+n+1);
for(int i=1;i<=n;i++)
{
if(num[i]>=0)
{
st=i;
break;
}
}
for(int i=1;i<=st;i++)
{
l=i;
r=n;
for(;l<=r;)
{
mid=(l+r)/2;
if(check(i,mid))
{
l=mid+1;
}
else
{
r=mid-1;
}
}
check(i,r);
}
cout<<maxx;
}