有关导数
是指函数的 切线(或者说函数图像相邻的两个点的直线)的斜率。表述为 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)=nxn−1 。
结论二: ∀ 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)(x−x0)+2!f′′(x0)(x−x0)2+...+n!f(n)(x0)(x−x0)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 (x−x0)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)(x−x0)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)(x−x0)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)(x−x0)+2!f′′′(x0)(x−x0)2+...+(n−1)!f(n)(x0)(x−x0)n−1
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)(x−x0)+2!f′′′′(x0)(x−x0)2+...+(n−2)!f(n)(x0)(x−x0)n−2
… … \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=2i−11−4i×ai(1≤i),求
a
n
a_n
an。
输入格式
一行一个正整数
n
(
1
≤
n
≤
1
0
6
)
n(1\le n\le 10^6)
n(1≤n≤106)。
输出格式
一行一个浮点数
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−(2i−1)ai+1 。
据大佬Freopen说,这个 a i + 1 a_{i+1} ai+1 的系数 2 i − 1 4 i \frac{2i-1}{4i} 4i2i−1 是“收敛的”(蒟蒻作者也没有搞懂是什么意思),于是他假设 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
4i2i−1≈0.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)=21x−21,f′′(x)=−41x−23,…(由导数结论一可得)。
将其在 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)(x−1)+2!f′′(1)(x−1)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×11−4×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×21−4×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×31−4×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×41−4×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=4n1−4n(n+1)(2n−1)+4n(n+1)(n+2)(2n−1)(2n+1)−⋯
虽然确实有无穷项,但是这个值收敛的很快。经试验,只需要约
1000
1000
1000 次,就可以达到
1
0
−
8
10^{-8}
10−8 的精度。当然不是我试验的,是标程这么打的。
#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;
}