1.前言:在很多题目里会涉及到递推公式的使用,然而大多数递推公式都是有很强的前后依赖性,第n项的求解依赖于n前边的几项。比如大名鼎鼎的fib数列。但是很多时候,我们要O(1)公式。本文简单的谈一下一些常见的递推公式的求解。
2.一阶线性递推。形如:
这种序列,显然是可以构造一个矩阵,然后利用矩阵快速幂求解。但是我们也可以求解它的通项公式。首先是特征方程:
我们把an,an-1,an-2分别看作二次项,一次项,和常数项。然后就可以得到一个一元二次方程:
我们把这个方程接一下,会得到两个根x1,x2。(这里在复数域下解方程)。然后通项公式:
在x1,x2是共轭复数时,采用复数的三角表示法给出。一般最常用的就是前两种。其中,A,B这些系数由前几项待定系数解出。
这样,其实就很轻松地推出了fib数理的通项公式。
例题:南昌网赛H。其实这个题出的很棒,但是由于数据有点水导致很多错误解法AC。真实的做法就是:
然后找一下sqrt(17)关于998244353的二次剩余,把这个公式写成了O(1)公式,但是还是只能O(logn)解决,依旧不行,O(log)的原因就是快速幂还需要O(logn),如何消除这个log?受到BSGS的启发,我们先预处理掉一部分幂,存下来然后每次在数组里面找,这样预处理之后就是O(1)的方案。
(2)一阶分式递推。 这种类型的叫做一阶分式递推。同理,我们做这个分式的特征方程:
这个方程也是二次方程,也会有两个根: x1,x2.所以简单推导一下:
首先是两个相异的根:
由于这里的x1,x2都是常数,所以两式相除可得:
OK,这里就显然等比数列了。
然后是两个相等的根:可以解出:x1=x2= .然后:
.
把这个分式拆一下,然后x1带入可得:
显然等差数列。
例题:沈阳网赛G。题目的意思就是用n个三角形和n个bar连成电路,然后问你它的总电阻是多少。
其实这个题也是一个好题,奈何推出来的式子太特殊,题目要求的精度也不是很高,不需要公式即可解决。
思路:首先我们设bn表式已经连好了n个三角形和n个bar。来推n+1
首先式bn和一个电阻为a的12并联,也就是:并联之后,再和23并联,这时和24串联,最后和34并联。按照电阻串并联的公式推一下,可以退出bn+1和bn的关系:
其实可以继续推下去把通项公式接出来,不过因为这个式子收敛的比较快,所以当n大于20左右时,就不会有精度的错误了,都按照20来做。所以没必要推公式,直接模拟就行。
#include<bits/stdc++.h>
double a;
double Solve(int n) {
if (n == 1) {
return 5.0 / 3.0 * a;
}
double b = Solve(n - 1);
double r = 3 * a + 1.0 / (1.0 / (3 * a) + 1.0 / a + 1.0 / b);
return 1.0 / (1 / (3.0 * a) + 1 / r);
}
const int N = 1e6 + 10;
char x[N];
int main() {
int T;
scanf("%d", &T);
while (T--)
{
scanf("%s", x);
int n;
if (strlen(x) > 1)n = 10;
else n = x[0] - '0';
scanf("%lf", &a);
printf("%.10f\n", Solve(n));
}
}