0)
(这个题的数据OJ没有补充,0<=N<=100000,K<=N,A[i]<=10^9)
二分法是有规律的暴力,那么二分的数列一定是有某种顺序,使得二分得到的数如果不符合某个条件,可以按规则再往左二分或再往右二分。
1)
之前用二分模拟划分情况,非常笨也非常麻烦,是不符合为了简洁高效而使用二分的思想。事后才知道,直接二分答案即可,因为二分效率非常高,找到答案所在的大概的区间位置,也就是二分所有可能的区间和,也不过是log(10^5)≈16,再遍历一遍这个找到的大概区间,从而找到最小的和,哪怕是最坏情况下,把所有和再遍历一遍,是O(n)=10^5,总共也不过1.6*10^6,是可以接受的。
还是应该把思路打开,用思想去做题,而不要太拘泥于题目的具体场景。
补充:如果加上 #include <iostream> 与 using namespace std(同时存在),自己定义的left 、right 与标准库中的冲突,因此编译报错二义性问题——...main.cpp|41|error: reference to 'left' is ambiguous| ......
//#include <iostream>
#include <string>
#include <stdio.h>
//using namespace std;
int n,k;
long long int sum=0;
int a[100010];
long long int left=0;
long long int right=0;
long long int mid;
int Date(){
int cnt=1;
long long int temp=mid;
for(int i=1;i<=n;i++){
if(mid<a[i]){
return -1;//当前二分到的数,过小
}
if(temp>=a[i]) temp-=a[i];
else if(temp<a[i]){
cnt++;
temp=mid-a[i];
}
}
if(cnt==k) return 0;
else if(cnt<k) return 1;//当前二分到的数,过大
else return -1;
}
int main()
{
while(~scanf("%d %d",&n,&k))
{
sum=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
left=0;
right=sum;
mid=(left+right)/2;
int cur=Date();
while(cur){
if(cur==-1) left=mid+1;
else if(cur==1) right=mid-1;
mid=(left+right)/2;
cur=Date();
}
for(mid=left;mid<=sum;mid++){
if(Date()==0){
printf("%ld\n",mid);
break;
}
}
}
return 0;
}
2)
Description
有n个菜鸟站成一排,Jason要按顺序虐他们一下。虐第i个菜鸟需要花费掉A[i]点RP,现在Jason打算分k天虐完这些菜鸟。Jason每天的RP总数是固定的,为了使RP最低的时候不会过低导致杯具,他希望这k天中虐菜花费RP最多的一天,花费的RP尽量少。求Jason在花费RP最多那天花费了了多少RP。
Input
第一行两个正整数n,k。
第二行为此数列A[i]。
Output
一个数,为题目所求答案。
Sample Input
5 22 1 3 4 5
Sample Output
9