目录
二分学习 +板子
一、查找 等于某个值的 位置(下标)/ 对应的变量
在不连续的数据中查找 即数组
int Bifi(int a[],int n,int x){
int l=0,r=n-1;
while(l<=r){
int mid=(l+r)/2;
if(x==a[mid])return mid;
if(x>a[mid])l=mid+1;
else r=mid-1;
}
retrn -1;
}
在连续的数据中查找 (仅限单调函数
xx f(xx ?){return 函数值;}
xx Bifi(xx l,xx r,xx y){
while(r-l> 精确最小误差 ){
int mid=(l+r)/2;
if(f(mid)>y)r=mid-精确最小误差;
else l=mid+精确最小误差;
}
retrn (l+r)/2;
}
二、查找 第一个大于等于某个值的 位置(下标)
可以用:lower_bound()代替参考资料
int Bifi(int l,int r,int x){
int pos;
while(l<=r){
int mid=l+r>>1;
if(dp[mid]>=x){
pos=mid;
r=mid-1;
}
else l=mid+1;
}
return pos;
}
若是查找 第一个大于某个值的位置
可以用:upper_bound()代替参考资料
将上面代码中的 if(dp[mid]>=x)改成if(dp[mid]>x)即:
int Bifi(int l,int r,int x){
int pos;
while(l<=r){
int mid=l+r>>1;
if(dp[mid]>x){
pos=mid;
r=mid-1;
}
else l=mid+1;
}
return pos;
}
三分学习
两个端点间取三等分,中间两个点哪一个的函数值更靠近最值,则取两个点中的另一个点为端点,
再循环上述操作
直至中间两个点无限逼近(或者说其差值小于误差值),则极值就为两点的中间的函数值
水题集
二分:
hdu 2199:找单调函数方程解 ->连续的二分
#include <bits/stdc++.h>
using namespace std;
//double f(double x){return 8*x*x*x*x +7*x*x*x +2*x*x+3*x+6; }
double f(double x){return 8*pow(x,4.0)+7*pow(x,3.0)+2*pow(x,2.0)+3*x+6; }
double Bifi(double y,double l,double r){
while(r-l>1e-7){
double mid=(r+l)/2;
if(f(mid)>y )r=mid-1e-7;
else l=mid+1e-7;
}
return (l+r)/2;
}
int main(){
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;scanf("%d",&t);
while(t--){
double y;scanf("%lf",&y);
if(y<6 || y>f(100)){printf("No solution!\n");continue;}
printf("%.4f\n",Bifi(y,0.0,100.0));
}
return 0;
}
三分:
hdu 2899:求凸性函数最值:一个函数三分
#include <bits/stdc++.h>
using namespace std;
double f(double x,double y){return 6*pow(x,7.0)+8*pow(x,6.0)+7*pow(x,3.0)+5*pow(x,2.0)-y*x; }
double Trfi(double y,double l,double r){
double a=(l*2+r)/3,b=(r*2+l)/3,ans=0.0;
while(b-a>1e-7){
if(f(b,y)>f(a,y))r=b;
else l=a;
a=(l*2+r)/3;b=(r*2+l)/3;
}
return f( (a+b)/2 ,y );
}
int main(){
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;scanf("%d",&t);
while(t--){
double y;scanf("%lf",&y);
printf("%.4f\n",Trfi(y,0.0,100.0));
}
return 0;
}
hdu 3714:求多个函数构成的图形函数的最值
分析:求F(x)=max(Si(x));
画图分析易知F(x)一定是一个下凸的图像,三分
这个题的精度要注意,还不会精度到底要怎么搞,我一般都取1e-7,这次wa了,取了1e-10过了。
#include <bits/stdc++.h>
using namespace std;
//把F[x]=max(s(x))表示出来;
int n;
struct node{double a,b,c;}p[10010];
double S(double a,double b,double c,double x){return a*x*x+b*x+c;}
double F(double x){
double m=S(p[1].a,p[1].b,p[1].c,x);
for(int i=2;i<=n;i++){
m=max(m, S(p[i].a,p[i].b,p[i].c,x) );
}
return m;
}
double Trfi(double l,double r){
double ll=(l*2+r)/3,rr=(r*2+l)/3;
while(rr-ll>1e-10){
if( F(ll)>F(rr) ) l=ll;
else r=rr;
ll=(l*2+r)/3,rr=(r*2+l)/3;
}
return F((rr+ll)/2);
}
int main(){
int t;scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].c);
}
printf("%.4f\n",Trfi(0.0,1000.0));
}
return 0;
}
这个题又学到了一个“代码技巧”:就是多个函数取最大值(最小值)的操作
wa多次 ?水题集?
二分:
poj:1905
做这个题做到怀疑智商了QAQ
分析:
由题意已知:L ,s ,0<h<L/2 ; 求 h;
那么知道S(R(h))的单调性就可以知道用二分还是三分求解了;
下面是错误分析(这段分析真的还以自己还有没有智商了)
根据 h 的范围;我对①式中的 h 求导;得出 r 随 h 的增大而减小(即单调减函数);然后我一看②式妥妥的单调增函数啊;然后我就判定这个复合函数为单调减函数了。
但是我突然发现我运行样例的时候,???,怎么都不对,我就去翻别人的题解,从别人的代码里我发现一个问题,就是这个复合函数是单调增的,然后我质疑了自己的思路,没问题啊,又求了很多次导;终于发现woc,那个式子②他不是单增啊,然后又发现,我不会求这个函数;
所以正确的分析应该是这样的:
h 增加,那个弧长一定是增加的啊,也就是我那个复合函数是单增的。woc我在想什么????想求导想疯了;
但翻别人写的题解的时候,我还是有收获的:
就是二分的时候精度问题:还可以通过直接二分100次解决,但是感觉不靠谱,我三分用了100,直接TLE了,别人的二分100次;但是吧现在还没遇到卡精度卡那么高的题,等以后吃亏了再来写写这个while(100);
#include <iostream>
#include <cmath>
using namespace std;
double L,n,c;
double f(double h){
double r=(4*h*h+L*L)/(8*h);
return 2*r*asin(L/(2*r));
}
double Bifi(double l,double r,double s){
while(r-l>1e-6){
double mid=(r+l)/2;
if( s>f(mid) )l=mid;
else r=mid;
}
return (r+l)/2;
}
int main(){
while(scanf("%lf%lf%lf",&L,&n,&c)){
if(L<0&&n<0&&c<0)break;
double s=(1+n*c)*L;
printf("%.3f\n",Bifi(0.0,L/2,s));
}
return 0;
}