///二分解决,学习了
#include<bits/stdc++.h>
using namespace std;
int a[100000+10];
int n; //天数
int m; //规定的分组数
/*判断用当前的mid值能把天数n分成几组*/
/*通过比较group与m的大小,对mid值进行优化*/
int binary(int key)
{
int sum=0;
int cnt=1; //当前mid值能把n天分成的组数(初始把全部天数作为1组)
for(int i=1; i<=n; i++) //从第一天开始向下遍历每天的花费
{
sum+=a[i]; //当前i天之和<=mid时,把他们归并到一组
if(sum>key) 注意这里的不取等,意思是该组中的的总数是允许等于mid的
{ //只有当它大于mid时才可以视为另一组
sum=a[i]; //则把前i-1天作为一组,第i天作为下一组的第一天
cnt++; //此时划分的组数+1
}
}
return cnt;
}
int main()
{
while(cin>>n>>m)
{
int low=0,high=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
low=max(low,a[i]); //把n天中花费最多的那一天的花费作为下界low(相当于把n天分为n组)
high+=a[i]; //把所有天数的总花费作为上界high(相当于把n天都分作1组)
}
/*
以下的二分是一个模板操作来着的,只要思想匹配就可以使用模板
这个模板的意思是 因为这个mid是有很多个数多可以满足的,但题目要求的是求出最小
所以使用的模板就是 在 一个有序的序列中,查找第一个大于某个数的下标
要的是第一个!!!!! 所以在二分的时候 需要将取等的情况放在high=mid-1的位置
目的就是为了不断让high向下指,使得mid不断的逼近第一个满足题意的值
最终3个肯定会指向同一个位置,此时会通过最后一次的比较得到答案
*/
/*谢谢之前博主的总结,让我受益匪浅,学习到很多东西,对恶人有更加全面的理解
总觉得二分最重要的一点,就是在边界细节的处理,只要理解这个,相信对二分有更加深刻的理解
还有另外几种模板,注意理解本质即可,需要的时候只要思想一致,就可以使用
这里有我之前看的那位博主的链接,需要的可以查阅下,表示很受用,谢谢
*/
int mid;
while(low<=high)
{
mid=low+((high-low)>>1);
int k=binary(mid);
if(k>m)
low=mid+1;
else
high=mid-1;
}
printf("%d\n",low);
}
return 0;
}
二分总结:https://blog.youkuaiyun.com/yefengzhichen/article/details/52372407(推荐)
//嘻嘻嘻,这是我第一次写的暴搜的结果,哈哈哈,用来验证二分算法思想的正确与否,哼,算法竞赛宝典居然有一组测试数据是错的,吓得我赶紧用暴搜检查
#include<bits/stdc++.h>
#include<map>
using namespace std;
#define N 100000+10
int a[N];
int sum[N]={0};
int ans,n,m;
void dfs(int k,int p,int Max)
{
if(k==m)
{
Max=max(Max,sum[n]-sum[p-1]);
ans=min(ans,Max);
return ;
}
for(int i=p; i<=n-m+k; i++)//注意这里的n-m+k不是单纯的份数,而是对应的下标最大的枚举数
{
int t=Max;
Max=max(Max,sum[i]-sum[p-1]);
dfs(k+1,i+1,Max);
Max=t;
}
}
int main()
{
while(cin>>n>>m)
{
ans=0x3f3f3f3f;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
dfs(1,1,0);
printf("%d\n",ans);
}
return 0;
}