• 学习笔记:三分法(唔,好像不是唉)


    明明保存了,却奇怪的消失了,真令人迷惑,只好再写一遍。
    题目链接:P3382 【模板】三分法
    我们知道极值处导函数值为(0),那么我们把这个函数的导数求出来,二分答案即可。
    刚刚学习了导数,来看一下与这题有关的导数法则。

    [[f(x)pm g(x)]'=f'(x)pm g'(x) ]

    那我们推导到更多加减法的求导,对于一个(n)次多项式(f(x))

    [f(x)=sumlimits_{i=0}^na_ix^i ]

    显然,它的导数是:

    [f'(x)=sumlimits_{i=0}^{n-1}(i+1)a_{i+1}x^i ]

    这个直接模拟就好了。

    关于多项式的求值

    对于高次项,容易想到对自变量(x)快速幂,不过这样是(mathcal O(nlog n))的,有没有更好的方法呢?
    有!
    早在很早以前,中国数学家秦九韶就提出了秦九韶算法,我们来举个栗子吧。
    有一个多项式(g(x)):

    [g(x)=ax^3+bx^2+cx+d ]

    我们这样化简一下:

    [g(x)=x(x(xa+b)+c)+d ]

    这样就能(mathcal O(n))了。

    double f(double g,int n)//求n次多项式f(g)的值
    {
    	double x=fuc[n];
    	for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
    	return x;
    }
    

    自己的想法

    在讲述秦九韶算法时,莫名发现一种奇妙算法:
    快速幂为什么慢呢?
    显然是重复处理了一些幂次,那我们直接暴算幂次即可,这样也是(mathcal O(n))的:

    double f(double g,double n)
    {
    	double x=1,ans=0;
    	for(int i=0;i<=n;i++) ans=ans+x*fuc[i],x*=g;
    	return ans;
    } 
    

    然后这道题就做完了:

    (Code):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define read(x) scanf("%d",&x)
    #define read_d(x) scanf("%lf",&x)
    double fuc[20];
    double a[20];
    int n;
    double l,r;
    double f(double g,int n)
    {
    	double x=fuc[n];
    	for(int i=1;i<=n;i++) x=g*x+fuc[n-i];
    	return x;
    }
    int main()
    {
    	read(n),read_d(l),read_d(r);
    	for(int i=n;i>=0;i--) read_d(a[i]);
    	//求导 
    	for(int i=n;i>=1;i--) fuc[i-1]=a[i]*i;
    	double mid;
    	for(int i=1;i<=100;i++)
    	{
    		mid=(l+r)/2;
    		if(f(mid,n-1)<0) r=mid;
    		else l=mid;
    	}
    	printf("%.5lf
    ",mid);
    	return 0;
    }
    

    那么你如果对于多项式函数的求导一般式一脸懵逼,那么直接按定义做就好了:
    我们知道导数的定义为:

    [f'(x)=limlimits_{mathitDelta x ightarrow 0}dfrac{f(x+mathitDelta x)-f(x)}{mathitDelta x} ]

    我们可以把(mathitDelta x)设成很小的数如(10^{-10}),然后就行了。
    大佬是这样做的,我来搬运代码:

    (Code):

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 15;
    const double eps = 1e-10;;
    int n;
    double L, R, a[N];
    double f(double x) {
    	double c[N];
    	c[n] = a[n];
    	for (int i = n - 1; i >= 0; --i) c[i] = c[i + 1] * x + a[i];
    	return c[0];
    }
    double check(double x) {
    	double dx = eps;
    	double dy = f(x + eps) - f(x);
    	return dy / dx;
    }
    int main() {
    	cin >> n >> L >> R;
    	for (int i = 0; i <= n; ++i) cin >> a[n - i];
    	double mid; 
    	while (R - L > eps) {
    		mid = (L + R) / 2;
    		if (check(mid) > 0) L = mid;
    		else R = mid; 
    	}
    	printf("%.5lf", L);
    	return 0;
    } 
    

    关于复杂度:
    二分(100)次的话就是(mathcal O(100n))了,或者写成( mathcal O(nlog eps))
    (ps):我自己(yy)的竟然比秦九韶算法快(8;ms)

  • 相关阅读:
    系统维护相关问题
    Python环境维护
    哈希表解决字符串问题
    论文笔记二:《A Tutoral on Spectral Clustering》
    论文笔记之哈希学习比较--《Supervised Hashing with Kernels》《Towards Optimal Binary Code Learning via Ordinal Embedding》《Top Rank Supervised Binary Coding for Visual Search》
    Java中String、StringBuffer、StringBuilder的比较与源 代码分析
    浙大pat1040 Longest Symmetric String(25 分)
    浙大pat1039 Course List for Student(25 分)
    浙大pat---1036 Boys vs Girls (25)
    百炼oj-4151:电影节
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12623204.html
Copyright © 2020-2023  润新知