黑龙江农垦科技职业学院喜迎寒假多校联赛2(快乐ak场)D题详解
从比赛到现在,终于算是想通了,记录一下。
AC代码
#include<iostream>
using namespace std;
typedef unsigned long long ull;
const int N = 1e6 + 10;
int n,m;
ull a[N],l,r;
bool check(ull mid)
{
ull sum = 0;
ull cnt = 1;
for(int i = 0;i < n;i ++)
{
sum += a[i];
if(sum > mid)
{
sum = a[i];
cnt ++;
}
}
if(cnt <= m)return true;
return false;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i = 0;i < n;i ++)
{
scanf("%llu",&a[i]);
r += a[i];
}
//cout << check(6) << endl;
while(l < r)
{
ull mid = (l + r) >> 1;
//mid >= m
if(check(mid))r = mid;
else l = mid + 1;
//cout << "l = " << l << " r = " << r << endl;
}
printf("%llu",l);
}
值得一提的是,这样写,就已经足够AC这个题,但是还有一处逻辑错误,二分的左边界应该是 m a x ( a [ i ] ) max(a[i]) max(a[i]),而不是0.
分析:
真正的划分过程如上,我们规定
m
i
d
mid
mid 这个数是能达到的最大值的最小值。这意味着 : 当
s
u
n
<
=
m
i
d
sun <= mid
sun<=mid 的时候,都可以划分成一个队伍。如果 >sum,就记录得到的队伍数量 +1,这样的划分,使得
m
i
d
mid
mid向着
a
n
s
ans
ans不断靠近。
图中,从左往右,能组成
c
n
t
cnt
cnt支队伍的数量是在逐渐减少的。
如果拿个人max,来作为划分边界,毫无疑问的,能划分到n个队伍。
m
i
d
mid
mid从左往右能划分的队伍的数量越来越少,在ans处,恰好能划分成m,这也就是我们的答案,如果 > ans,肯定能划分成m支队伍,所以:
是从这里转换的。
下面是个人错误的点
之所以迷了这么久,是因为划分的条件搞错了。
之前我是这么划分的,导致更新区间一直是错误的状态。
能分成 m 队,这个是很容易做到的事情,因为在 mid = 个人最大 的时候,这个条件已经达成了。总实力的不断提高,能划分成的队伍肯定是越来越少的, > ans 组成一队,实际上 mid 的值是没有具体意义的,最后二分出来的值,肯定不是答案。