二分專題練習(挑戰程序設計)

目錄

 

1.最大化最小值

poj3258:River Hopscotch

poj3273:Monthly Expense

poj3104:Drying

poj3045:Cow Acrobats

最大化平均值

poj2976:Dropping tests

poj3111:K Best

查找第k大的值

poj3579:Median

poj3685:Matrix

最小化第k大的值

poj2010:Moo University - Financial Aid

poj3662:Telephone Lines

其他

poj1759:Garland

poj3484:Showstopper


1.最大化最小值

poj3258:River Hopscotch

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5e4+10;
int a[maxn],L,n,m;

bool check(int d){
	int pre=a[0],cnt=0;
	for(int i=1;i<=n;i++){
		if(a[i]-pre<d){
			cnt++;
			continue;
		} 
		pre=a[i];
	}
	if(cnt>m||a[n+1]-pre<d) return false;
	return true;
}

int main(){
	scanf("%d%d%d",&L,&n,&m);
	a[0]=0,a[n+1]=L;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a,a+n+1);
	int l=0,r=L+1;    //r的取值要比答案區間大點,所以這裏+1 
	while(r-l>1){   //這裏的答案區間 [l,r) ,所以二分到區間長度爲1時,答案就出來了 
		int mid=l+(r-l)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%d\n",l);
	return 0;
}

 

poj3273:Monthly Expense

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const int INF=1e9+10;
int a[maxn],n,m;

bool check(int d){
	int sum,p=1;
	for(int i=1;i<=m;i++){
		sum=a[p++];
		while(p<=n&&sum+a[p]<=d){
			sum+=a[p++];
		}
		if(p>n) return true;
	}
	return false;
}

int main(){
	scanf("%d%d",&n,&m);
	int mx=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		mx=max(mx,a[i]);
	}
	int l=mx,r=INF,ans=mx;   
	while(r-l>=0){   //這裏的答案區間 [l,r] ,所以二分到區間長度爲空時,答案就出來了 
		int mid=l+(r-l)/2;
		if(check(mid)){
			ans=mid;
			r=mid-1;	
		}else l=mid+1;
	}
	printf("%d\n",ans);
	return 0;
}

/*
7 5
10 10 10 10 10 10 10

1 1
10000
*/

 

poj3104:Drying

題解:可以想到對時間進行二分,但對於衣服風乾的總時間無法預定。

大佬很詳細的思路,可以參考下~(在公式推導的地方有點問題,注意下就行)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int a[maxn],n,k;

/*設使用吹風機的時間爲t,則每件衣服最多可以有mid-t的水可以風乾,t*k+(mid-t)>=a[i],t>=(a[i]-mid)/(k-1)*/

bool check(int mid){
	long long sum=0;  //注意sum有可能超int,最好所有的變量都設爲long long 
	for(int i=n;i>0;i--){
		if(a[i]<=mid) break;
		sum+=ceil(1.0*(a[i]-mid)/(k-1));
	}
	return sum<=mid;
}

int main(){
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		
		sort(a+1,a+1+n);
		scanf("%d",&k);
		int ans=0;
		if(k==1) ans=a[n];
		else{
			int lb=0,ub=a[n]+1;   //[lb,ub]
			while(ub-lb>=0){
				int mid=lb+(ub-lb)/2;
				if(check(mid)){
					ans=mid;
					ub=mid-1;
					//printf("ans=%d\n",ans);
				}else lb=mid+1;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

poj3045:Cow Acrobats


最大化平均值

poj2976:Dropping tests

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e3+10;
const double eps=1e-6;
int a[maxn],b[maxn];
double y[maxn];
int n,k;


bool check(double x){
	for(int i=0;i<n;i++){
		y[i]=a[i]-x*b[i];
	}
	sort(y,y+n);
	
	double sum=0;
	for(int i=n-1;i>=k;i--){
		sum+=y[i];
	}
	return sum>=0;
}

int main(){
	while(~scanf("%d%d",&n,&k)){
		if(n==0&&k==0) break;
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		for(int i=0;i<n;i++)
			scanf("%d",&b[i]);
			
		double lb=0,rb=1;
		while(fabs(rb-lb)>=eps){
			double mid=lb+(rb-lb)/2;
			if(check(mid)) lb=mid;
			else rb=mid;
		}
		printf("%.0f\n",100*lb);
	}
	return 0;
}

poj3111:K Best

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const double eps=1e-6;
int n,k;

struct Node{
	int id;
	double v,w,y;
	bool operator < (const Node &a) const{
		if(y>=a.y) return true;
		return false;
	}
}res[maxn];

bool check(double x){
	for(int i=1;i<=n;i++){
		res[i].y=res[i].v-x*res[i].w;
	}
	sort(res+1,res+1+n);
	
	double sum=0;
	for(int i=1;i<=k;i++){
		sum+=res[i].y;
	}
	return sum>=0;
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",&res[i].v,&res[i].w);
		res[i].id=i;
	}
			
	double lb=0,rb=1e8;
	while(fabs(rb-lb)>=eps){
		double mid=lb+(rb-lb)/2;
		if(check(mid)) lb=mid;
		else rb=mid;
	}
	//printf("%f\n",lb);

	for(int i=1;i<=k;i++){
		if(i==1) printf("%d",res[i].id);
		else printf(" %d",res[i].id);
	} 
	printf("\n");
	return 0;
}

查找第k大的值

poj3579:Median

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int a[maxn],n,m;

int work(int x){
	int lb=1,ub=n,ans;
	while(lb<=ub){
		int mid=lb+(ub-lb)/2;
		if(a[mid]<=x){
			ans=mid;
			lb=mid+1;
		}else ub=mid-1;
	}
	return ans;
}



bool check(int mid){  //在序列裏,如果小於等於mid的數大於等於m個,true 
	int cnt=0;
	for(int i=1;i<=n;i++){
		cnt+=work(a[i]+mid)-i;
	} 
	return cnt>=m;
}

int main(){
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		m=(n*(n-1)/2+1)/2;  //中位數的位置
		sort(a+1,a+1+n);
		int ans=0,lb=0,ub=a[n]-a[1];
		while(lb<=ub){
			int mid=lb+(ub-lb)/2;
			if(check(mid)){
				ans=mid;
				ub=mid-1;	
			}else
				lb=mid+1;
		}
		printf("%d\n",ans);
	}
	
	return 0;
}

poj3685:Matrix

 


最小化第k大的值

poj2010:Moo University - Financial Aid


poj3662:Telephone Lines


其他

poj1759:Garland

/*
	h[i]=(h[i-1]+h[i+1])/2-1;
	h[i+1]=2*(h[i]+1)-h[i-1];
	h[3]=2*h[2]+2-A
	證明:B的值與h[2]成正相關的。 
	只要證出這點,直接二分h[2]即可。 
	證明如下:(大概) 
	其實遞推的過程中,h[i],h[i+1]化成只含h[2]和常數的式子,
	很容易看出h[i]中h[2]的係數大於h[i-1]中h[2]的係數,也就是h[i+1]=a*h[i]+b(a>0) 
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const double eps=1e-6;
int n;
double A,ans;

bool check(double x){
	double a=A,b=x,tmp;
	for(int i=3;i<=n;i++){
		tmp=b;
		b=2*(b+1)-a;
		a=tmp;
		if(b<0) return false;
	}
	ans=b;
	return true;
}

int main(){
	while(~scanf("%d%lf",&n,&A)){
		double lb=0,ub=A;
		while(ub-lb>=eps){
			double mid=lb+(ub-lb)/2;
			if(check(mid)) ub=mid;
			else lb=mid;
		}
		printf("%.2lf\n",ans);
	}
	
	return 0;
}


 

poj3484:Showstopper

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章