1. 程式人生 > >分巧克力(二分法)

分巧克力(二分法)

 兒童節那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友們。
    小明一共有N塊巧克力,其中第i塊是Hi x Wi的方格組成的長方形。
    為了公平起見,小明需要從這 N 塊巧克力中切出K塊巧克力分給小朋友們。切出的巧克力需要滿足:
    1. 形狀是正方形,邊長是整數  
    2. 大小相同  
例如一塊6x5的巧克力可以切出6塊2x2的巧克力或者2塊3x3的巧克力。
當然小朋友們都希望得到的巧克力儘可能大,你能幫小Hi計算出最大的邊長是多少麼?
輸入
第一行包含兩個整數N和K。(1 <= N, K <= 100000)  
以下N行每行包含兩個整數Hi和Wi。(1 <= Hi, Wi <= 100000) 


輸入保證每位小朋友至少能獲得一塊1x1的巧克力。   
輸出
輸出切出的正方形巧克力最大可能的邊長。
樣例輸入:
2 10  
6 5  
5 6  
樣例輸出:

2

分析:

我們知道,在1~100000之間的任何一個數x,將各個“大塊的巧克力”按照邊長為x的正方形進行切割,如果切割的塊數大於等於K,就能夠實現每個小朋友都有一份的目標。我們要找的是最大的那個x,不妨記為maxX(如果最大值為maxX,那麼1到maxX之間的任何數x都可以作為正方形巧克力的邊長)。該題乍一看似乎與查詢沒關係,但是仔細分析,可以將原問題理解為:在1~100000之間尋找一個數maxX,使得將巧克力按照邊長maxX進行切分,切分成的份數要大於等於

K,而如果按照maxX+1進行切割,將不再能夠切出K塊。

那如何判斷能否以mid為邊長分割出大於等於K塊正方形巧克力呢?假設n塊巧克力的長和寬分別儲存在兩個一維陣列H[100000]和W[100000]的n個元素裡。

由於一塊大小為H*W(長為H,寬為W)的巧克力,可以切割成的邊長為mid的正方形巧克力的塊數為:(H/mid)*(W/mid),所以n塊巧克力所切割成的總塊數count可以按照下面的方式計算出來:

int count = 0, i;

      for(i = 1; i<= n; i++){

             count+= (H[i]/x)*(W[i]/x);

      }

顯然當count大於等於K時,就可以切割出能夠分給小朋友的巧克力,否則就切割不出。

#include<iostream>
#include<cstring>

using namespace std;

int n,k,a[110000],b[110000];
bool ok(int x)
{
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		cnt+=(int(a[i]/x)*int(b[i]/x));
		if(cnt>=k)return true;	
	}
	return false;
	
 } 
int main()
{
	
	cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
	int l=0;int r=100004;
	while(r-l>1){
		int m=(l+r)>>1;
		if(ok(m))l=m;
		else r=m;
	}
	cout<<l<<endl;
	
	return 0;
 }