分治 2025/1/14
File Modal

int Binary_Search(int lim,int rim) {//max legal key
	int mid;
	while(l<r){
		mid=(l+r+1)>>1;
		if(check(mid)){
			l=mid;
		}else{
			r=mid-1;
		}
	}
	return l;
}

int Binary_Search(int lim,int rim) {//min legal key
	int mid;
	while(l<r){
		mid=(l+r)>>1;
		if(check(mid)){
			r=mid;
		}else{
			l=mid+1;
		}
	}
	return l;
}

double Binary_Search(double lim,double rim){
	double mid;
	while(rim-lim>eps){
		mid=(lim+rim)/2;
		if(check(mid)){//  or   
			l=mid;     //		r=mid;
		}else{         //
			r=mid;     //		l=mid;
		}
	}
	return l;
}



Question 01 [ACP2036 数列分段]
注意组数从一开始! 
需要特判有单个元素大于 lim! 
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1999940;
int n,m;
long long lable[N],tot;
bool check(long long lim){
	int ans=1;//groups starts from 1!
	long long cnt=0;
	for(int i=1;i<=n;i++){
		if(lable[i]>lim)return false;
		if(cnt+lable[i]>lim)cnt=0,++ans;
		cnt+=lable[i];
	}
	return ans<=m;
}
long long ans(long long lim,long long rim){
	long long mid;
	while(lim<rim){
		mid=(lim+rim)/2;
		if(check(mid)){
			rim=mid;
		}else{
			lim=mid+1;
		}
	}
	return rim;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&lable[i]),tot+=lable[i];
	printf("%lld",ans(0,tot));
	return 0;
}


Question 02 [ACP1902 最短跳跃距离]
注意去掉离起点和终点一倍间距内的石头!
Code 
#include<bits/stdc++.h>
using namespace std;
const int N=50009;
int l,n,m,lable[N]; 
bool check(int lim){
	int np=0,kill=0,st=1,ed=n;
	while(st<=n&&lable[st]<lim)++st,++kill;
	while(ed>=1&&l-lable[st]<lim)--ed,++kill;
	np=lable[st];
	for(int i=st+1;i<=ed;i++){
		if(lable[i]-np<lim)kill++;
		else np=lable[i];
	}
	return kill<=m;
}
int ans(int lim,int rim){
	int mid;
	while(lim<rim){
		mid=(lim+rim+1)>>1;
		if(check(mid)){
			lim=mid;
		}else{
			rim=mid-1;
		}
	}
	return lim;
}
int main(){
	scanf("%d%d%d",&l,&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&lable[i]);
	printf("%d",ans(1,l));
	return 0;
}


Question 03 [ACP2043 愤怒的牛]
二分答案模板题
 
Code
#include<bits/stdc++.h>
using namespace std;
const int N=150009;
int n,m,lable[N]; 
inline bool check(int distance){
	int np=lable[1],cow=1;
	for(int i=2;i<=n;i++){
		if(lable[i]-np>=distance){
			++cow,np=lable[i];
		}
	}
	return cow>=m;
}
int ans(int lim,int rim){
	int mid;
	while(lim<rim){
		mid=(lim+rim+1)>>1;
		if(check(mid)){
			lim=mid;
		}else{
			rim=mid-1;
		}
	}
	return lim;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&lable[i]);
	sort(lable+1,lable+n+1);
	printf("%d",ans(1,lable[n]-lable[1]));
	return 0;
} 


Question 04 [ACP2044 Best Cow Fences] 
给定一个长度为n的正整数序列A,求一个平均数最大的,长度不小于L的子串

Answer 
本题集毒瘤毒瘤和毒瘤于一身,令人RP--
首先本题为01规划问题 
即要求收益比代价的值最大
定义收益数组V,代价数组W

    V[1]+V[2]+v[3]+...+V[n]-------------------------- =ans (其中可能有不选的,ans为理想值) 
 	W[1]+w[2]+w[3]+...+W[n]
 	  
去分母得
ans*W[1]+ans*W[2]+...+ans*W[n]=V[1]+V[2]+...+V[n]
(V[1]-ans*W[1])+(V[2]-ans*W[2])+...+(V[n]-ans*W[n])=0 
易知在本题中W[i]=1
(因为求平均数每个数的加入都会使分母加一) 
所以
(V[1]-ans)+(V[2]-ans)+...+(V[n]-ans)=0 
我们想要找是否有长度足够且符合该条件的字段
定义 (V[i]-ans) 为 delta[i] 
问题转为 delta 长度大于等于 L 的最大正字段和
使用前缀和求解即可
注意实数二分且直接取整本题要取 rim
example
lim=4.999999999999999 -> 4999
rim=5.000000000000001 -> 5000

Code
#include<bits/stdc++.h>
using namespace std;
const int N=150009;
const double eps=1e-9;
int n,m,lable[N],tot;
double delta[N];
bool check(double average){
	for(int i=1;i<=n;i++)delta[i]=(double)lable[i]-average+delta[i-1];//前缀和 
	//求长度大于等于 m 的最大子段和 
	double mini=0.0,answer=-1.0;
	for(int i=1,j=m;j<=n;i++,j++) {
		answer=max(delta[j]-mini,answer);
		mini=min(mini,delta[i]);
	}
	if(answer>0)return true;
	return false;
}
double ans(double lim,double rim){
	double mid;
	while(rim-lim>eps){
		mid=(lim+rim)/2.0;
		if(check(mid)){
			lim=mid;
		}else{
			rim=mid;
		}
	}
	return rim*1000;
	//用 lim 不行!
	//lim=4.99999999999999999 
	//rim=5.00000000000000001
	//取rim 
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m; 
	for(int i=1;i<=n;i++)cin>>lable[i],tot+=lable[i];
	cout<<(int)ans(0.0,tot);
	return 0;
}

Question 05 [ACP2045 曲线]
有 k 个二次函数 f(x)=ax^2+bx+c (0<=a<=1000)
ff(x)=max(所有 f(x))ff(x)[0,1000]上的最大值

Answer
易知 ff 在[0,1000][单调递增/有单峰]
三分模板

Code
#include<bits/stdc++.h>
using namespace std;
const int N=19994;
const double eps=1e-8;
int n,a[N],b[N],c[N];
double mid1,mid2,lim,rim,ans;
double M(double x){
	double ans=-1e10;
	for(int i=1;i<=n;i++)ans=max(ans,(double)a[i]*x*x+(double)+b[i]*x+(double)c[i]);
	return ans;
}
int main(){
	//ios::sync_with_stdio(false);
	//cin.tie(0),cout.tie(0);
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i],&b[i],&c[i]);
		lim=0,rim=1000;
		while(rim-lim>eps){
			mid1=lim+(rim-lim)/3.0,mid2=rim-(rim-lim)/3.0;
			if(M(mid1)<=M(mid2))rim=mid2;else lim=mid1;
		}
		ans=M((lim+rim)/2.0);
		printf("%.4lf\n",ans);
	}
	return 0;
}

Question 06 [ACP2048 灯泡]
三分+推式子

Code
#include<bits/stdc++.h>
using namespace std;
const int N=199994;
double H,h,D;
inline double f(double k){return D-k+H-(D*H-D*h)/k;}
double ans(double lim,double rim){
	double m1,m2;
	while(rim-lim>1e-9){
		m1=(lim*2.0+rim)/3.0,m2=(rim*2.0+lim)/3.0;
		if(f(m1)>f(m2))rim=m2;else lim=m1;
	}
	return f(lim);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%lf%lf%lf",&H,&h,&D);
		printf("%.3lf\n",ans(D-h*D/H,D));
	}
	return 0;
}
posted on   2025ing  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示