泰勒板题?

有关导数

是指函数的 切线(或者说函数图像相邻的两个点的直线)的斜率。表述为 f ′ ( x ) = lim ⁡ x → ∞ f ( x + Δ x ) − f ( x ) Δ x f'(x)=\lim_{x\rightarrow \infty}\frac{f(x+\Delta x)-f(x)}{\Delta x} f(x)=limxΔxf(x+Δx)f(x)

结论一 ∀ f ( x ) = x n , f ′ ( x ) = n x n − 1 \forall f(x)=x^n,f'(x)=nx^{n-1} f(x)=xn,f(x)=nxn1

结论二 ∀ f ( x ) = f 1 ( x ) + f 2 ( x ) , f ′ ( x ) = f 1 ′ ( x ) + f 2 ′ ( x ) \forall f(x)=f_1(x)+f_2(x),f'(x)=f_1'(x)+f_2'(x) f(x)=f1(x)+f2(x),f(x)=f1(x)+f2(x)

结论三 ∀ f ( x ) = c × g ( x ) , f ′ ( x ) = c × g ′ ( x ) \forall f(x)=c\times g(x),f'(x)=c\times g'(x) f(x)=c×g(x),f(x)=c×g(x)

有关泰勒展开

概述

泰勒展开,是用另一种方式来 部分表示 已知函数(对于大多数函数来说,可以在全体实数域上表示)。

其思想,是在 x = x 0 x=x_0 x=x0 处使得 g ( x ) = f ( x ) g(x)=f(x) g(x)=f(x) 且其 增长率 相同。

如何使得增长率相同?——导数相同!完全相同是不可能的。——再次泰勒展开 模拟!

所以,用递归的定义,就应该 大概 是这个样子(实际上是有系数的):

Function Taylor(f(x)){
	return f(x0)+(x-x0)*Taylor(f'(x0));
	/* x-x0 是为了让 x=x0 时,只存在前面的 f(x0) 一项 */
}

来看看百度百科上的定义:

若函数 f ( x ) f(x) f(x) 在包含 x 0 x_0 x0 的某个闭区间 [ a , b ] [a,b] [a,b] 上具有 n n n 阶导数,且在开区间 ( a , b ) (a,b) (a,b) 上具有 ( n + 1 ) (n+1) (n+1) 阶导数,则对闭区间 [ a , b ] [a,b] [a,b] 上任意一点 x x x ,成立下式: f ( x ) = f ( x 0 ) 0 ! + f ′ ( x 0 ) 1 ! ( x − x 0 ) + f ′ ′ ( x 0 ) 2 ! ( x − x 0 ) 2 + . . . + f ( n ) ( x 0 ) n ! ( x − x 0 ) n + R n ( x ) f(x)=\frac{f(x_0)}{0!}+\frac{f'(x_0)}{1!}(x-x_0)+\frac{f''(x_0)}{2!}(x-x_0)^2+...+\frac{f^{(n)}(x_0)}{n!}(x-x_0)^n+R_n(x) f(x)=0!f(x0)+1!f(x0)(xx0)+2!f(x0)(xx0)2+...+n!f(n)(x0)(xx0)n+Rn(x)
其中, f ( n ) f^{(n)} f(n) 表示 f ( x ) f(x) f(x) n n n 阶导数,等号后的多项式称为函数 f ( x ) f(x) f(x) x 0 x_0 x0 处的泰勒展开式,剩余的 R n ( x ) R_n(x) Rn(x) 是泰勒公式的余项,是 ( x − x 0 ) n (x-x_0)^n (xx0)n 的高阶无穷小。

用我的话来说:

f ( x ) = f ( x 0 ) + ∑ k = 1 + ∞ f ( k ) ( x 0 ) k ! ( x − x 0 ) k f(x)=f(x_0)+\sum_{k=1}^{+\infty}\frac{f^{(k)}(x_0)}{k!}(x-x_0)^k f(x)=f(x0)+k=1+k!f(k)(x0)(xx0)k

f ( k ) f^{(k)} f(k) 表示 f f f k k k 次导数。没有导数还展开个屁。你试试狄利克雷函数?

尝试

试着计算泰勒展开式 g ( x ) g(x) g(x) 中的每一阶导数:

解释: x 0 x_0 x0 为常数,故 f ( x 0 ) f(x_0) f(x0) 为常数,在取导后消失;对于 f ( i ) ( x 0 ) j ! ( x − x 0 ) j \frac{f^{(i)}(x_0)}{j!}(x-x_0)^j j!f(i)(x0)(xx0)j ,左边是常数。

g ′ ( x ) = f ′ ( x 0 ) 0 ! + f ′ ′ ( x 0 ) 1 ! ( x − x 0 ) + f ′ ′ ′ ( x 0 ) 2 ! ( x − x 0 ) 2 + . . . + f ( n ) ( x 0 ) ( n − 1 ) ! ( x − x 0 ) n − 1 g'(x)=\frac{f'(x_0)}{0!}+\frac{f''(x_0)}{1!}(x-x_0)+\frac{f'''(x_0)}{2!}(x-x_0)^2+...+\frac{f^{(n)}(x_0)}{(n-1)!}(x-x_0)^{n-1} g(x)=0!f(x0)+1!f(x0)(xx0)+2!f(x0)(xx0)2+...+(n1)!f(n)(x0)(xx0)n1

g ′ ′ ( x ) = f ′ ′ ( x 0 ) 0 ! + f ′ ′ ′ ( x 0 ) 1 ! ( x − x 0 ) + f ′ ′ ′ ′ ( x 0 ) 2 ! ( x − x 0 ) 2 + . . . + f ( n ) ( x 0 ) ( n − 2 ) ! ( x − x 0 ) n − 2 g''(x)=\frac{f''(x_0)}{0!}+\frac{f'''(x_0)}{1!}(x-x_0)+\frac{f''''(x_0)}{2!}(x-x_0)^2+...+\frac{f^{(n)}(x_0)}{(n-2)!}(x-x_0)^{n-2} g(x)=0!f(x0)+1!f(x0)(xx0)+2!f(x0)(xx0)2+...+(n2)!f(n)(x0)(xx0)n2

… … \dots\dots

可以发现, g ( x ) g(x) g(x) 的每一阶导数在 x = x 0 x=x_0 x=x0 处的取值都与 f f f 相同!

泰勒展开实验图
这是在几何画板1中进行的尝试。可以发现,这两个函数是一模一样的!

题目

题目描述
有一个数列 a a a,满足 a 1 = 1.5 − 1 , a i + 1 = 1 − 4 i × a i 2 i − 1 ( 1 ≤ i ) a_1=\sqrt{1.5}-1,a_{i+1}=\frac{1-4i\times a_i}{2i-1}(1\le i) a1=1.5 1,ai+1=2i114i×ai(1i),求 a n a_n an

输入格式
一行一个正整数 n ( 1 ≤ n ≤ 1 0 6 ) n(1\le n\le 10^6) n(1n106)

输出格式
一行一个浮点数 a n a_n an (保留至小数点后 8 8 8 位)。

思路和代码

暴力递推

直接上代码——

#include <cstdio>
#include <cmath>
double ans[105]; int n;
int main(){
	scanf("%d",&n);
	ans[1] = sqrt(1.5)-1.0;
	for(int i=1; i<n; ++i)
		ans[i+1] = (1-4.0*i*ans[i])/(2.0*i-1);
	printf("%.8f\n",ans[n]);
	return 0;
}

让我们来试点数据。

测试一
输入10
输出0.01748215
还行。

测试二
输入100
输出1209114318209024.75000000
正确输出0.00167499

很明显, W r o n g    A n s w e r \tt Wrong\;Answer WrongAnswer 了。样例都过不了。

倒推法

考虑将公式等价变换,得到 a i = 1 − ( 2 i − 1 ) a i + 1 4 i a_i=\frac{1-(2i-1)a_{i+1}}{4i} ai=4i1(2i1)ai+1

据大佬Freopen说,这个 a i + 1 a_{i+1} ai+1 的系数 2 i − 1 4 i \frac{2i-1}{4i} 4i2i1 是“收敛的”(蒟蒻作者也没有搞懂是什么意思),于是他假设 a 1000000 = 0 a_{1000000}=0 a1000000=0 ,倒推回来得 a 1 = 1.5 − 1 a_1=\sqrt{1.5}-1 a1=1.5 1 ,恰好。然后他 A c c e p t a b l e \tt Acceptable Acceptable 了……

于是倒推的精度更高(忽略大佬 我的理解是, 2 i − 1 4 i ≈ 0.5 \frac{2i-1}{4i}\approx 0.5 4i2i10.5,如果 a n a_{n} an 偏差了 1 1 1 ,那么在计算 n n n 次后就只偏差了大约 0. 5 n 0.5^n 0.5n ,在 n → ∞ n\rightarrow \infty n 时可以忽略不计),没有精度问题。

#include <cstdio>
#include <cmath>
double ans[1000005]; int n;
int main(){
	ans[1000000] = 0;
	for(int i=999999; i>=1; --i)
		ans[i] = (1-(2*i-1)*ans[i+1])/(4*i);
	scanf("%d",&n);
	printf("%.8f\n",ans[n]);
	return 0;
}

泰勒展开

终于进入正解了!Freopen大佬秀我一脸。

f ( x ) = x − 1 f(x)=\sqrt{x}-1 f(x)=x 1 ,有 f ′ ( x ) = 1 2 x − 1 2 ,    f ′ ′ ( x ) = − 1 4 x − 3 2 ,    … f'(x)=\frac{1}{2}x^{-\frac{1}{2}},\;f''(x)=-\frac{1}{4}x^{-\frac{3}{2}},\;\dots f(x)=21x21,f(x)=41x23,(由导数结论一可得)。

将其在 x 0 = 1 x_0=1 x0=1 处(为什么?因为这是 无穷项 的泰勒展开式,若 x 0 ≠ 1 x_0\ne 1 x0=1 ,则涉及到的 x 0 x_0 x0 的幂将难以计算)泰勒展开,得到了最最最最关键的东西:

f ( x ) = f ( 1 ) 0 ! + f ′ ( 1 ) 1 ! ( x − 1 ) + f ′ ′ ( 1 ) 2 ! ( x − 1 ) 2 + ⋯ f(x)=\frac{f(1)}{0!}+\frac{f'(1)}{1!}(x-1)+\frac{f''(1)}{2!}(x-1)^2+\cdots f(x)=0!f(1)+1!f(1)(x1)+2!f(1)(x1)2+

现在展开很麻烦。我们用它来干嘛的来着?—— a 1 a_1 a1 的有理表达式!很明显, a 1 = f ( 1.5 ) a_1=f(1.5) a1=f(1.5) ,直接将 x = 1.5 x=1.5 x=1.5 代入泰勒展开式中,就可以得到:

a 1 = 1 4 × 1 − 1 4 × 2 + 1 × 3 4 × 2 × 3 − ⋯ a_1=\frac{1}{4\times 1}-\frac{1}{4\times 2}+\frac{1\times 3}{4\times 2\times 3}-\cdots a1=4×114×21+4×2×31×3

用递推公式硬推,得:

a 2 = 1 4 × 2 − 1 × 3 4 × 2 × 3 + 1 × 3 × 5 4 × 2 × 3 × 4 − ⋯ a_2=\frac{1}{4\times 2}-\frac{1\times 3}{4\times 2\times 3}+\frac{1\times 3\times 5}{4\times 2\times 3\times 4}-\cdots a2=4×214×2×31×3+4×2×3×41×3×5

a 3 = 1 4 × 3 − 1 × 5 4 × 3 × 4 + 1 × 5 × 7 4 × 3 × 4 × 5 − ⋯ a_3=\frac{1}{4\times 3}-\frac{1\times 5}{4\times 3\times 4}+\frac{1\times 5\times 7}{4\times 3\times 4\times 5}-\cdots a3=4×314×3×41×5+4×3×4×51×5×7

a 4 = 1 4 × 4 − 1 × 7 4 × 4 × 5 + 1 × 7 × 9 4 × 4 × 5 × 6 − ⋯ a_4=\frac{1}{4\times 4}-\frac{1\times 7}{4\times 4\times 5}+\frac{1\times 7\times 9}{4\times 4\times 5\times 6}-\cdots a4=4×414×4×51×7+4×4×5×61×7×9

发现规律了吗?

a n = 1 4 n − ( 2 n − 1 ) 4 n ( n + 1 ) + ( 2 n − 1 ) ( 2 n + 1 ) 4 n ( n + 1 ) ( n + 2 ) − ⋯ a_n=\frac{1}{4n}-\frac{(2n-1)}{4n(n+1)}+\frac{(2n-1)(2n+1)}{4n(n+1)(n+2)}-\cdots an=4n14n(n+1)(2n1)+4n(n+1)(n+2)(2n1)(2n+1)

虽然确实有无穷项,但是这个值收敛的很快。经试验,只需要约 1000 1000 1000 次,就可以达到 1 0 − 8 10^{-8} 108 的精度。当然不是我试验的,是标程这么打的。

#include<cstdio>
int main(){
    int n; scanf("%d",&n);
    double b = 0, t = 1/(n*4.0);
    for(int j=1; j<=1000; ++j)
        b += t, t = -(2*n+2*j-3)*t/4.0/(n+j);
    printf("%.8f\n",(double)b);
    return 0;
}

  1. 数学软件,见官网 ↩︎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值