二分与三分(分治)

二分与三分(分治)

[整数二分]
写法1(求最小值最大):
int l=1,r=n;
while(l<r){ // 答案可行区间
int mid=(l+r+1)/2;//加1修正 |--------------------|
if(check(mid)){//mid成立,舍去左边。 L|______________m_______________|R
l=mid;
}else{ // mid不成立,舍去右边。 答案可行区间
r=mid-1;// |------------|
} // L|______________m_______________|R
}
写法2(求最大值最小):
int l=1,r=n;
while(l<r){
int mid=(l+r)/2;// 答案可行区间
if(check(mid)){//mid成立,舍去右边。 |-------------------|
r=mid; // L|______________m_______________|R
}else{ //mid不成立,舍去左边。 答案可行区间
l=mid+1; // |------------|
} // L|______________m_______________|R
}
[实数二分]
(double)
double l,r,eps=1e-7;//eps为精度
while(r-l>eps){
if(check(mid)){//或
l=mid; //r=mid
}else{ //
r=mid; //l=mid
}
}
二分例题:
1.[数列分段]
accoders的2046【一本通提高篇二分与三分】 数列分段II
luogu 的 P1182 数列分段 Section II
思路:
求最大值最小,运用[整数二分]写法2,l为数组中最大,
r为total.
code:
#include<bits/stdc++.h>
using namespace std;
int a[1000010],n,m;
int check(int x){
int sum=0,ans=1;//ans为当前有几组,sum为当前组总和
for(int i=1;i<=n;i++){
if(sum+a[i]<=x){
sum+=a[i];
}else{
/* 当你把l设为0,r设为1e9时:
if(a[i]>x){
return 0;
}
*/
ans++;
sum=a[i];
}
}
return ans<=m;
}
int main(){
cin>>n>>m;
int l=0,r=0;
for(int i=1;i<=n;i++){
cin>>a[i];
l=max(l,a[i]);//l为最大值
r+=a[i]; //r为total
}
while(l<r){
int mid=l+r>>1;
if(check(mid)){
r=mid;
}else{
l=mid+1;
}
}
cout<<l<<"\n";
return 0;
}
2.[河中跳房子]
accoders的 1902【一本通基础分治】河中跳房子
思路:
求最小值最大化,[整数二分]写法1,二分跳跃长度,
l为最小间距,r为L。
#include<bits/stdc++.h>
using namespace std;
int L,n,m,a[50010],l=2e9,r=2e9;
int check(int x){
int ans=0,s=0;
for(int i=1;i<=n+1;i++){
if(a[i]-s>=x){
s=a[i];
}else{
ans++;
}
}
return ans<=m;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>L>>n>>m;
r=L;
for(int i=1;i<=n;i++){
cin>>a[i];
l=min(l,a[i]-a[i-1]);
}
l=min(l,L-a[n]);
a[n+1]=L;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
cout<<l;
return 0;
}
3.[愤怒的牛]
accoders的【一本通提高篇二分与三分】 愤怒的牛 2043
luogu的 P1824 进击的奶牛
思路:
求最小值最大化,[整数二分]写法1,二分牛的间隔距离,
l为最小间距,r为第一牛棚与最后牛棚的间距。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[100010],l=2e9,r;
int check(int x){
int ans=1,s=1;
for(int i=2;i<=n;i++){
if(a[i]-a[s]>=x){
ans++;
s=i;
}
}
return ans>=m;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
for(int i=2;i<=n;i++){
l=min(l,a[i]-a[i-1]);
}
r=a[n]-a[1];
while(l<r){
int mid=l+r+1>>1;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
cout<<l;
return 0;
}
4.[Best Cow Fences]
accoders的【一本通提高篇二分与三分】 Best Cow Fences 2044
luogu的 P10450 [USACO03MAR] Best Cow Fences G
思路:
求长度至少为L的子串的平均值最大,[实数二分],l为0.0,r为total。
check运用前缀和求平均。
code:
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n,m;
double l=0.0,r,eps=1e-5,b[100010];
int check(double x){
for(int i=1;i<=n;i++){
b[i]=(b[i-1]+a[i]*1.0-x)*1.0;
}
double ans=0;
for(int i=m;i<=n;i++){
ans=min(ans,b[i-m]);
if(b[i]-ans>=0.0){
return 1;
}
}
return 0;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
r+=a[i];
}
while(r-l>eps){
double mid=(l+r)/2.0;
if(check(mid)){
l=mid;
}else{
r=mid;
}
}
cout<<int(r*1000);
return 0;
}
5[木材加工]
accoders 的 木材加工9052
思路:
[整数二分]写法1的板子,没啥好说的。
code:
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n,k,l=0,r=-1;
int check(int x){
int ans=0;
for(int i=1;i<=n;i++){
ans+=a[i]/x;
}
return ans>=k;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
r=max(r,a[i]);
}
while(l<r){
int mid=l+r+1>>1;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
cout<<l;
return 0;
}
[三分]
1.
accoders【一本通提高篇二分与三分】 曲线 2045
luogu P1883 【模板】三分 | 函数
code:
#include<bits/stdc++.h>
using namespace std;
int n;
double a[100010],b[100010],c[100010],eps=1e-11;
double check(double x){
double mx=-1e9;
for(int i=1;i<=n;i++){
mx=max(mx,a[i]*x*x+b[i]*x+c[i]);
}
return mx;
}
int main(){
int T;
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i]>>c[i];
}
double l=0,r=1000;
while(r-l>eps){
double mid1=l+(r-l)/3,mid2=r-(r-l)/3;
if(check(mid1)<=check(mid2)){
r=mid2;
}else{
l=mid1;
}
}
printf("%.4lf\n",check(r));
}
return 0;
}
2.
accoders的【一本通提高篇二分与三分】 灯泡 2048
luogu的 P5931 [清华集训2015] 灯泡
code:
#include<bits/stdc++.h>
using namespace std;
int t;
double hb,h,d;
double check(double x){
return d-x+hb-(d*hb-d*h)/x;
}
int main(){
cin>>t;
while(t--){
cin>>hb>>h>>d;
double l=d-h*d/hb,r=d;
while(r-l>1e-9){
double mid1=l+(r-l)/3.0,mid2=r-(r-l)/3.0;
if(check(mid1)<=check(mid2)){
l=mid1;
}else{
r=mid2;
}
}
printf("%.3lf\n",check(r));
}
return 0;
}
posted @   lbh123  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示