二分的题目2 数列分段

来源:互联网 发布:excel导入数据按钮 编辑:程序博客网 时间:2024/05/14 08:48

[问题描述] 

对于给定的一个长度为N正整数数列A[i],现要将其分成MMN)段,并要求每段连续,且每段最大值最小。 关于最大值最小:

 

例如一数列 4 2 4 5 1 要分成 段 将其如下分段:

[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

 

[输入文件]

 

输入文件 divide_b.in 的第 1 行包含两个正整数 NM,第 2 行包含 N 个空格隔开的非 负整数 A[i],含义如题目所述。

 

[输出文件]

 

输出文件 divide_b.out 仅包含一个正整数,即每段和最大值最小为多少。

 

[样例输入]

5 3

4 2 4 5 1

 

[样例输出]

 

6

 

[数据规模与约定]

对于 20%的数据,有 N10

对于 40%的数据,有 N1000

对于 100%的数据,有 N100000MN A[i]之和不超过 109


[分析]

第一眼看到这个题目——动态规划无疑了!可是转眼一想,如果用动态规划那么这个时间复杂度就直接超神了,是不可行的方法。
因为最近在搞二分,所以可以知道,我们可以将答案二分,对于每一个答案判断是否能够满足要求。如果不能满足要求,则缩小一半搜索范围,反之也可以缩小一半搜索范围。所以时间复杂度为O(logMAXANS*N)。至于怎样判断答案是否满足要求,就不用我赘述了吧!

#include <iostream>#include <cstdio>#include <stdint.h>using namespace std;#define ULL unsigned long longint n,m;ULL l,r; int s[1000010];int num[1000010]; int maxn[1000010];ULL MAXN; ULL ans=18446744073709551615ULL;bool pan(int l){int i=0,cnt=1;ULL sum=0;while(1){i++;sum+=s[i];if(sum>l){if(s[i]>l)return false;sum=s[i];cnt++;if(cnt>m)return false; }if(i==n)break;}return true;}int main(){freopen("divide_b.in","r",stdin);freopen("divide_b.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&s[i]),MAXN+=s[i];l=1;r=MAXN;while(l<=r){ULL mid=(l+r)/2;bool flag=pan(mid);if(flag){if(ans>mid)ans=mid;if(l==r)break;r=mid;}else l=mid+1;}printf("%I64u\n",ans);return 0;}

1 0
原创粉丝点击