【模板】三分法
題目描述
如題,給出一個N次函數,保證在范圍[l,r]內存在一點x,使得[l,x]上單調增,[x,r]上單調減。試求出x的值。
輸入輸出格式
輸入格式:
第一行一次包含一個正整數N和兩個實數l、r,含義如題目描述所示。
第二行包含N+1個實數,從高到低依次表示該N次函數各項的系數。
輸出格式:
輸出為一行,包含一個實數,即為x的值。四舍五入保留5位小數。
說明
時空限制:50ms,128M
數據規模:
對于100%的數據:7<=N<=13
思路:
這是一道三分的模板題,在這里我講一下三分
三分是什么??:
三分是一種優化的暴力,從他的名字就可以知道,這是一種很類似于二分的方法,通過一系列操作時復雜度由O(n)降到O(logn)
三分能干什么?
求單峰多次函數最值位置(近似值)
如何實現三分?(這個是重點)
我們先看一幅圖(picture by luogu)
現在我們的已知條件有峰所在的區間和函數表達式,這就很好辦
首先我們取區間中點
然后取離中點很近的兩個點(距離必須小于等于要求精度),并求出它們的函數值
這時候通過判斷函數值的大小就可以知道此處是遞增還是遞減
如果遞增,那點就在左區間,峰在其右,區間左端點就變成區間中點
反之亦然
一直縮小區間大小
到滿足精度時,答案就呼之欲出
一點小優化:
高中的同學應該都知道有個東西叫秦九韶算法
它可以將a0+a1*x^1+a2*x^2……an^xn這個高復雜度的東西
優化為an(x+an-1(x……a1(x+a0)))這個線性的式子
復雜度下降了一個log
很好使
見代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#define rii register int i
using namespace std;
int n;
double xs[15],l,r,final,mid;
double eps=0.000001;
double dxs(double z)
{
double ans=0;
for(rii=n;i>=0;i--)
{
ans=ans*z+xs[i];
}
return ans;
}
int main()
{
cin>>n>>l>>r;
for(rii=n;i>=0;i--)
{
cin>>xs[i];
}
eps=0.000001;
while(1)
{
if(fabs(r-l)<eps)
{
final=r;
break;
}
mid=(l+r)/2;
if(dxs(mid+eps)>dxs(mid-eps))
{
l=mid;
}
else
{
r=mid;
}
}
printf("%.5lf",final);
}
總結
- 上一篇: Unicode编码与中文互转
- 下一篇: 怎么创建具有真实纹理的CG场景岩石?