数 列 分 段 S e c t i o n I I 数列分段\ Section\ II 数列分段 Section II
题目链接:luogu P1182
题目
对于给定的一个长度为 N N N的正整数数列 A − i A-i A−i,现要将其分成 M ( M ≤ N ) M(M≤N) M(M≤N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列
4
4
4
2
2
2
4
4
4
5
5
5
1
1
1要分成
3
3
3段
将其如下分段:
[
4
[4
[4
2
]
[
4
2][4
2][4
5
]
[
1
]
5][1]
5][1]
第一段和为
6
6
6,第
2
2
2段和为
9
9
9,第
3
3
3段和为
1
1
1,和最大值为
9
9
9。
将其如下分段:
[
4
]
[
2
[4][2
[4][2
4
]
[
5
4][5
4][5
1
]
1]
1]
第一段和为
4
4
4,第
2
2
2段和为
6
6
6,第
3
3
3段和为
6
6
6,和最大值为
6
6
6。
并且无论如何分段,最大值不会小于
6
6
6。
所以可以得到要将数列
4
4
4
2
2
2
4
4
4
5
5
5
1
1
1要分成
3
3
3段,每段和的最大值最小为
6
6
6。
输入
第
1
1
1行包含两个正整数
N
N
N,
M
M
M。
第
2
2
2行包含
N
N
N个空格隔开的非负整数
A
i
A_i
Ai ,含义如题目所述。
输出
一个正整数,即每段和最大值最小为多少。
样例输入
5 3
4 2 4 5 1
样例输出
6
数据范围
对于
20
%
20\%
20%的数据,有
N
≤
10
N≤10
N≤10;
对于
40
%
40\%
40%的数据,有
N
≤
1000
N≤1000
N≤1000;
对于
100
%
100\%
100%的数据,有
N
≤
100000
,
M
≤
N
,
A
i
N≤100000,M≤N, A_i
N≤100000,M≤N,Ai之和不超过
1
0
9
10^9
109。
思路
这道题就是一道二分。
就二分答案,看看最少要分成多少段。超过
m
m
m段就不可以,答案在右边;否则就可以,答案在左边。
最后输出
l
l
l即可
代码
#include<cstdio>
#define max(x,y) (x)>(y)?(x):(y)
using namespace std;
int n,m,a[100001],l,r,temp,ans;
int main()
{
scanf("%d%d",&n,&m);//读入
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);//读入
l=max(l,a[i]);//找到最小答案
r+=a[i];//找到最大的答案
}
while (l<r)//二分
{
int mid=(l+r)/2;
ans=1;temp=0;//初始化
for (int i=1;i<=n;i++)//统计最少要分成多少段
if (a[i]+temp>mid)
{
ans++;
if (ans>m) break;
temp=a[i];
}
else temp+=a[i];
if (ans>m) l=mid+1;//超过了m段(不行)
else r=mid;//没有超过(可以)
}
printf("%d",l);//输出
return 0;
}