序列(二分)
1769: 序列
题目描述
给定一个长度为n的序列,要求将其分成m段序列,每一段连续,并使得每一段和的最大值尽可能小。
输入
第一行两个整数n,m。
第二行n个整数,代表序列。
输出
一行一个整数,代表每一段和的最大值的最小值。
样例输入
5 3
4 2 4 5 1
样例输出
6
分析:
我们首先要二分出最大值的最小值
没啥好说的:
scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) scanf("%d",&a[i]); int r=2e9,l=0; while(l+1!=r) { int mid=(l+r)/2; if(check(mid)/*如果符合*/==1) { r=mid; } else { l=mid; } }
如何判断最小呢?
先看样例
假设最小值是6
我们先让4当一段的开始
再看2,4+2<=6,所以让4 2形成一段
由于4+6>6
那么后面的4就又是一段的开始,以此类推
所以函数check这样写:
int check(int k) { int ans=0,num=0; for(int i=1; i<=n; i++) { if(a[i]>k) { return 0; } if(a[i]+num<=k) { num+=a[i]; } else { num=a[i]; ans++; } } ans++; if(ans<=m) { return 1; } else { return 0; } }
ok
全代码:
#include<bits/stdc++.h> using namespace std; int n,m,a[1e6+10]= {0}; int check(int k) { int ans=0,num=0; for(int i=1; i<=n; i++) { if(a[i]>k) { return 0; } if(a[i]+num<=k) { num+=a[i]; } else { num=a[i]; ans++; } } ans++; if(ans<=m) { return 1; } else { return 0; } } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); } int r=2e9,l=0; while(l+1!=r) { int mid=(l+r)/2; if(check(mid)==1) { r=mid; } else { l=mid; } } printf("%d",r); return 0; }

浙公网安备 33010602011771号