做法:贪心+二分
题意解读:
这题是我发的上一篇题解的题目的升级版。大意为给定一个长度为
N
N
N序列
a
i
(
i
∈
[
1
,
N
]
,
i
∈
N
?
)
a_i(i\in[1,N],i\in\mathbb N^*)
ai?(i∈[1,N],i∈N?),将其分成
M
M
M段,要求每段连续,并且使每段和的最大值最小。
相信大家如果眼睛不瞎
(
L
J
Z
:
我
瞎
呢
)
(LJZ:我瞎呢)
(LJZ:我瞎呢)都能看到上面加粗的五个字:最大值最小。当题目中出现了类似的字眼时,就表示大概率这题的答案具有单调性,可以二分解决。
(
O
W
:
今
年
t
g
必
考
二
分
)
(OW:今年tg必考二分)
(OW:今年tg必考二分)
思路:
我们设这个最小值为
K
K
K。我们略加思考可以发现:当
K
K
K十分的小时,一定可以存在一种分组,使组数
M
K
>
M
(
举
个
例
子
:
每
个
数
自
成
一
组
。
)
M_K>M(举个例子:每个数自成一组。)
MK?>M(举个例子:每个数自成一组。),此时的
K
K
K值都是符合题意的。而当
K
K
K逐渐增长到一个临界点以后,
M
K
M_K
MK?将小于
M
M
M,此时的
K
K
K都不符合题意。所以这个临界点
(
设
为
K
0
)
(设为K_0)
(设为K0?)满足:
{
?
M
x
∈
[
1
,
M
0
]
,
M
均
符
合
题
意
。
?
M
x
∈
(
M
0
,
+
∞
]
,
M
均
不
符
合
题
意
。
\begin{cases} \forall M_x\in[1,M_0],M均符合题意。\\ \forall M_x\in(M_0,+\infty],M均不符合题意。 \end{cases}
{?Mx?∈[1,M0?],M均符合题意。?Mx?∈(M0?,+∞],M均不符合题意。? 受到这个
M
0
M_0
M0?性质的启发,我们定义函数:
C
(
x
)
=
{
0
,
x
>
M
0
1
,
x
≤
M
0
C(x)=\begin{cases} 0,x>M_0\\ 1,x\leq M_0 \end{cases}
C(x)={0,x>M0?1,x≤M0?? 然后取
l
=
x
m
i
n
=
max
?
(
a
i
)
,
即
M
=
n
。
r
=
x
m
a
x
=
s
u
m
(
a
i
)
,
即
M
=
1
。
l=x_{min}=\max(a_i),即M=n。\\r=x_{max}=sum(a_i),即M=1。
l=xmin?=max(ai?),即M=n。r=xmax?=sum(ai?),即M=1。
二分求出临界值即可。
A
C
c
o
d
e
AC code
ACcode:
#include<bits/stdc++.h>
using namespace std;
int n, m, a[100005],l,r;
long long s[100005];
inline void read()
{
cin >> n >> m;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
l = max(a[i], l);
r += a[i];
}
}
inline bool C(int x)
{
int tot=0,num=0;
for(int i=1;i<=n;i++)
{
if(tot+a[i]<=x)tot+=a[i];
else tot=a[i],num++;
}
return num>=m;
}
int main()
{
read();
while(l<=r)
{
int mid=(l+r)>>1;
if(C(mid))
{
l = mid+1;
}
else
{
r = mid-1;
}
}
cout << l << endl;
return 0;
}
|