求得是最小力度R,R最大显然不超过最左边干草堆与最右边干草堆的距离。
有了下界(0)和上界,容易想到二分(估计很多人考场上都想到了)
二分力度,并判断是否可行。
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
double l=0,r=1.0*(a[n] - a[1])/2;
int bash = 70;
while(r-l>eps && --bash)
{
double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.1lf",l);
实数域二分可以限制批次,1e9范围70次完全够。
eps是精度,我设置为1e-7。
然后重点是如何判断方案可行。
答案是:暴力判断。
二分下包你要打哪里,lower_bound得到左边和右边最靠近的干草堆。
然后暴力的向左和向右扩散,得到你最左边炸到哪和最右边炸到哪。
如果左右都无法扩散到边界,则这个力度不可能。
如果只是其中一边无法扩散到,那就把 mid 往那边移动。
如图:
所以我们暴力的去判断可行性。
bool check(double k)
{
double l = a[1], r = a[n];
int bash = 70;
while (r - l > eps && --bash)
{
double mid = (l + r) / 2;
bool f1, f2;
f1 = f2 = true;
//左边和右边能否到达
int pos = lower_bound(a + 1, a + 1 + n, mid) - a; //显而易见
int left = pos - 1, right = pos; //左边和右边
double now = mid, force = k; //打在哪以及力度
while (left > 0)
{
if (now - a[left] > force) //打不到
{
f1 = false;
break;
}
while (left > 0 && now - a[left] <= force) //能以force的力波及到最远距离
{
left--;
}
now = a[left + 1], force--; //题目要求
}
now = mid, force = k;
while (right <= n) //类似
{
if (a[right] - now > force)
{
f2 = false;
break;
}
while (right <= n && a[right] - now <= force)
{
right++;
}
now = a[right - 1], force--;
}
if (!f1 && !f2)
{
return false;
}
if (!f1)
{
r = mid;
}
else if (!f2)
{
l = mid;
}
else
{
return true;
}
}
return false;
}
然后就Accepted了。
代码都给出了,改不 Accepted 就离谱了。