数列分段 Section II
思路:凡是题目里出现要求“最大值最小”或“最小值最大”(或者是解读题意后发现),那么一般使用二分答案。每段可以用前缀和求出,接着二分答案。因为每段和的最大值肯定大于小于数组中的最大值,所以二分的l要去数组中的最大值,如果取的小的话可能会得到和比最大值小的数,比如
输入 : 3 3 3 4 5 输出:5
题目描述
对于给定的一个长度为 $N$ 的正整数数列 $A_{1\sim N}$,现要将其分成 $M$($M\leq N$)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列 $4\ 2\ 4\ 5\ 1$ 要分成 $3$ 段。
将其如下分段:
$$[4\ 2][4\ 5][1]$$
第一段和为 $6$,第 $2$ 段和为 $9$,第 $3$ 段和为 $1$,和最大值为 $9$。
将其如下分段:
$$[4][2\ 4][5\ 1]$$
第一段和为 $4$,第 $2$ 段和为 $6$,第 $3$ 段和为 $6$,和最大值为 $6$。
并且无论如何分段,最大值不会小于 $6$。
所以可以得到要将数列 $4\ 2\ 4\ 5\ 1$ 要分成 $3$ 段,每段和的最大值最小为 $6$。
输入格式
第 $1$ 行包含两个正整数 $N,M$。
第 $2$ 行包含 $N$ 个空格隔开的非负整数 $A_i$,含义如题目所述。
输出格式
一个正整数,即每段和最大值最小为多少。
样例 #1
样例输入 #1
5 3
4 2 4 5 1
样例输出 #1
6
提示
对于 $20\%$ 的数据,$N\leq 10$。
对于 $40\%$ 的数据,$N\leq 1000$。
对于 $100\%$ 的数据,$1\leq N\leq 10^5$,$M\leq N$,$A_i < 10^8$, 答案不超过 $10^9$。
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N = 100010;
int n, m;
int a[N], s[N];
bool check(int u)
{
int t = 0, cnt = 1;
for (int i = 1; i <= n; i++)
{
if (s[i] - s[t] > u)
{
cnt++;
t = i - 1;
}
if (cnt > m) return false;
}
return true;
}
int main()
{
scanf("%d%d", &n, &m);
int mmax = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
s[i] = s[i - 1] + a[i];
mmax = max(mmax, a[i]);
}
int l = mmax, r = s[n];
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%d", l);
return 0;
}