1. 程式人生 > 資訊 >騰訊音樂旗下波點音樂上線“評論外顯”功能

騰訊音樂旗下波點音樂上線“評論外顯”功能

題目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1436

思路:很明顯的二分,以mid為假定的和的最大值中的最小值

首先邊界需要找一下

大邊界為全部數字的和

小邊界為數列中最大的那個,因為我們“最大值的最小值”無論如何也不會小於那個大數

然後,假定值mid就找出來了

以這個mid來給數列分段

如果分段少於要求的段數,那就證明數字估大了,需要向裡收

否則就往大了算

需要注意的是,在我們得到l和r時還需要一次判斷

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100001],l=-1e6,r=0;
int f(int mid){//判斷用的函式
	int i,sum=0,g=1;//sum為假定值鋪路,g是分段用的
	for(i=1;i<=n;++i){
		sum+=a[i];//
		if(sum>mid){//大於了我們假定的最大值
			sum=a[i];
			g++;//分一段
		}
	}
	if(g<=m){//段數少了,證明數估大了(等於的作用在後面)
		return 1;//返回真
	}
	return 0;//否則返回假
}
int main(){
	int i;
	scanf("%d%d",&n,&m);//常規操作
	for(i=1;i<=n;++i){
		scanf("%d",&a[i]);
		l=max(l,a[i]);//假定值的最小值
		r+=a[i];//假定值的最大值
	}
	while(r-l>1){
		int mid=(l+r)/2;
		if(f(mid)){//對假定值進行驗證
            //返回真,說明估大了
			r=mid;//往小了收
		}
		else{
			l=mid;//往大了收
		}
	}
	if(f(l)){
        //目前光憑藉上面的while,我們無法確定是l還是r
        //函式內等於號的作用就在這一步驗證上
		printf("%d",l);
	}
	else{
		printf("%d",r);
	}
	return 0;
}

總結:題目給予了一個數列,要求我們分段

分段後一段的和是一個,n段的和就是n個

在這n箇中找到一個最大值,這是第二個“一個”

無數種分法代表無數個“一個”,找到最小的“一個”

思路簡述就是“假設最小值進行判斷“,考二分的動機極其明顯

難點在於2邊界和結尾的判斷