今天给大家整点二分加贪心的题
题意
这个题是说在一个走廊上有n个房间,2个宿管从两端向中间查询,当宿管发现房间里的人数不足b个时,就记录下并锁门,两个宿管各自记录一边的,特别的,当n为奇数时,左边的宿管多查一个房间,求两个宿管记录数最大值的最小值。(P&S:当人数多于b个时,学生可以藏在床底下以躲过宿管的查房)
思路
像这种题,一看就是个二分题,那么我们该怎么验证可行性呢?
很容易想到如果一个房间不能满足,那么我们的最优策略就是留下一个空房间,将人往中间集中
所以可以得到中间一定满足的是一段连续的序列,故我们可以二分这个序列的最左端(也可以说是最右端),然后得到一个最大值。
如图:
代码
具体操作见代码
bool check(int x)
{
ll dis = 1ll * d * (x + 1);
int p1 = 1, p2 = n, s1 = x + 1, s2 = n - x;
for (int i = 1; i <= n; i++)
a[i] = t[i];
while (s1 < s2)
{
int tmp = b;
while (a[p1] < tmp) tmp -= a[p1++];
a[p1] -= tmp;
if (p1 - s1 > dis)
return 0;
if (n % 2 == 1 && s1 == (n + 1) / 2)
break;
tmp = b;
while (a[p2] < tmp)
tmp -= a[p2--];
a[p2] -= tmp;
if (s2 - p2 > dis)
return 0;
dis += d, s1++, s2--;
}
return 1;
}
int main()
{
rd(n), rd(d), rd(b);
for (int i = 1; i <= n; i++)
rd(t[i]);
int l = 0, r = (n + 1) / 2, ans;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
r = mid - 1, ans = mid;
else
l = mid + 1;
}
pt(ans);
return 0;
}