目录
常见的二分方法
求>=x中最小的一个
int search() {
while(l<r) {
int mid = (l+r)>>1;
if(a[mid]>=x) r = mid; else l = mid+1;
}
return a[l];
}
求<=x中最大的一个
int search() {
int mid = (l+r+1)>>1; //如果不+1,就会造成l不变化的死循环
if(a[mid]<=x) l = mid; else r = mid-1;
return a[l];
}
实数域确定精度的二分法
int search() {
while(l+eps<r) {
double mid = (l+r)/2;
if(calc(mid)) r = mid; else l = mid;
}
}
实数域上不确定精度的二分方法
此种方法通常精度较高。
int search() {
for(int i=0;i<100;i++) {
double mid = (l+r)/2;
if(calc(mid)) r = mid; else l = mid;
}
}
例题:poj2018
题目链接
http://poj.org/problem?id=2018
题意
要求一段长度至少为L的,平均数最大的子序列。并且输出这个平均值。
题解
首先,我们来想一个问题,如何求 一段长度为L,且它们的和最大 的子序列。很显然,我们可以用下面这一段代码来求
double ans = -1e10;
double min_val = 1e10;
for(int i=L;i<=n;i++) {
min_val = min(min_val , sum[i-L]);
ans = max(ans, sum[i] - min_val);
}
用一个小技巧来维护最小的min_val,然后用前缀和来求,这样能保证和最大,且必定大于L。
那么本题也就迎刃而解了,枚举平均值,然后用每个值先减去平均值,再求它们的和,如果和>0,那么说明还可以更大,所以l=mid,依次类推。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
double a[maxn],b[maxn],sum[maxn];
int n,L;
int main()
{
cin>>n>>L;
for(int i=1;i<=n;i++)
scanf("%lf",&a[i]);
double l = -1e6, r = 1e6;
while(l+eps<r) {
// cout<<l<<" "<<r<<endl;
double mid = (l+r) / 2;
for(int i=1;i<=n;i++)
b[i] = a[i]-mid;
for(int i=1;i<=n;i++)
b[i] += b[i-1];
double ans = -1e10;
double min_val = 1e10;
for(int i=L;i<=n;i++) {
min_val = min(min_val,b[i-L]);
ans = max(ans,b[i]-min_val);
}
if(ans>=0) l = mid; else r = mid;
}
cout<<int(r*1000)<<endl;
return 0;
}

665

被折叠的 条评论
为什么被折叠?



