其他分享
首页 > 其他分享> > 数列分段II(信息学奥赛一本通 1436)(洛谷 1182)

数列分段II(信息学奥赛一本通 1436)(洛谷 1182)

作者:互联网

【题目描述】

对于给定的一个长度为N的正整数数列A[i],现要将其分成M(M≤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],含义如题目所述。

【输出】

仅包含一个正整数,即每段和最大值最小为多少。

【输入样例】

5 3
4 2 4 5 1

【输出样例】

6

最小值最大(或是最大值最小)问题,这类双最值问题常常选用二分法求解。本题就是一道典型的“二分答案”模型。
因为每段和最大值的取值区间是[ max(a[1],a[2],a[3]……a[n]) , sum(a[1],a[2],a[3]……a[n]) ],所以就二分l和r,令mid=l+r>>1,每次进行check,计算当mid为最大值的情况下可以分成的段数cnt,

详见代码——

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+5;
 4 int a[N];
 5 int n;
 6 int m,q,w,ans,p,tot;
 7 int read()
 8 {
 9     int f=1;char ch;
10     while((ch=getchar())<'0'||ch>'9')
11         if(ch=='-')f=-1;
12     int res=ch-'0';
13     while((ch=getchar())>='0'&&ch<='9')
14         res=res*10+ch-'0';
15     return res*f;
16 }
17 void write(int x)
18 {
19     if(x<0)
20     {
21         putchar('-');
22         x=-x;
23     }
24     if(x>9)write(x/10);
25     putchar(x%10+'0');
26 }
27 bool check(int s)
28 {
29     int cnt=1,now=0;
30     for(int i=1;i<=n;i++)
31     {
32         if(a[i]+now<=s)now+=a[i];
33         else
34         {
35             cnt++;
36             now=a[i];
37         }
38     }
39     return cnt<=m;
40 }
41 int main()
42 {
43     n=read();m=read();int ma=-1,sum=0;
44     for(int i=1;i<=n;i++)
45     {
46         a[i]=read();
47         ma=max(ma,a[i]);
48         sum+=a[i];
49     }
50     int l=ma,r=sum;
51     while(l<=r)
52     {
53         int mid=l+r>>1;
54         if(check(mid))
55         {
56             ans=mid;r=mid-1;
57         }
58         else l=mid+1;
59     }
60     write(ans);
61     return 0;
62 }

 

标签:1436,cnt,ch,洛谷,int,最大值,1182,mid,每段
来源: https://www.cnblogs.com/ljy-endl/p/11388118.html