给大家普及一个知识,只要看到最大值最小或最小值最大等字样就往二分上想吧!
然后是正解部分:
我们可以二分答案;
对于每次二分的区间取中间值mid,并对其进行check()判断;
如果所有段的最大值为mid时可以分成m段(注意,如果此时分成的段比m还小,那么也是可行的,因为你可以随便拆拆就能拆成m段,但显然可能不是最优的解),那么我们就将二分区间更改为(l,mid),因为(mid+1,r)区间所有的答案均可行且都不是最优的。否则将区间改为(mid+1,r);
另外说明一下,二分的退出条件是l==r,并记录ans等于此时的r。
然后输出ans就好了
#include <bits/stdc++.h> using namespace std; int n,m; int a[100010],sum[100010]; int ans; bool check(int x) { for(int i=1;i<=n;i++){ if(sum[i]-sum[i-1]>x){ return 0; } } int tmp=0; int cnt=0; for(int i=1;i<=n;i++){ if(sum[i]-tmp>x){ tmp=sum[i-1]; ++cnt; i--; } } if(cnt+1>m) return 0; return 1; } void erfen(int l,int r) { if(l==r){ ans=l; return; } int mid=(l+r)/2; if(check(mid)) erfen(l,mid); else erfen(mid+1,r); } int main () { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } erfen(1,sum[n]); cout<<ans; }