文章目录
打表法
1.情景分析
当遇到某些问题,已经求得数列的一部分时,要求给定任意项的下标,返回该项的权值。
比如现在有一个数列:1,4,9,16,25,…
2.处理思路
主要有2种题型:
- 一种是要求推导出通项的题目,这类题目需要推导出前几项,然后根据前几项得到通项公式 f ( x ) f(x) f(x),最后根据通式预测 f ( k ) f(k) f(k),见:ICPC 2017 南宁区域赛L. Twice Equation
- 另一种是存在的答案本身就很少,比如给定的n是 1 0 18 10^{18} 1018,但是当 n > = 100000 n >= 100000 n>=100000后,就 不存在答案 或者答案 非常稀疏,这类题目就需要将全部的表给打出来,因为表本身就非常少,见:ICPC 2016 北京区域赛 K - JiLi Number
对于预测的推导通式的题型 f ( x ) f(x) f(x),这里给出一些推导 f ( x ) f(x) f(x)的方法。
2.1 观察法
2.1.1 普通性质
对于比较简单的算式,可以直接发现其性质:比如给定数列:1, 2, 4, 8, …我可以清楚地知道它就是2的幂次方。
2.1.2 特殊数列
给定的数列是一些特殊数列的前几项,比如:
斐波那契数列:0, 1, 1, 2, 3, 5, 8
哈代-拉马努金数列:1, 1, 2, 3, 5, 7, 11, 15
卡特兰数:1, 1, 2, 5, 14, 42, 132
2.2 插值法
2.2.1 差分法
对于一个数列:1, 2, 4, 10, 23, 46, 82, …
它的一阶数列为:1, 2, 6, 13, 36, …
它的二阶数列为:1, 4, 7, 10, 13, …
它的三阶数列为:3, 3, 3, 3, …
发现三阶数列为常数列,因此原数列1, 2, 4, 10, 23, 46就被称为三阶等差数列。每一个高阶等差数列都有一个多项式的通项公式。
将所有的序列写为如下的形式:
C n 1 a 1 a 2 a 3 a 4 a 5 . . . C_{n}^1\ \ \ \ \ \ a_1\ \ \ \ \ \ a_2\ \ \ \ \ \ a_3\ \ \ \ \ \ a_4\ \ \ \ \ \ a_5\ \ \ \ \ \ ... Cn1 a1 a2 a3 a4 a5 ...
C n 2 b 1 b 2 b 3 b 4 . . . C_n^2\ \ \ \ \ \ \ \ \ \ \ b_1\ \ \ \ \ \ \ b_2\ \ \ \ \ \ \ b_3\ \ \ \ \ \ \ b_4\ \ \ \ \ \ \ ... Cn2 b1 b2 b3 b4 ...
C n 3 c 1 c 2 c 3 . . . C_n^3\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c_1\ \ \ \ \ \ \ \ c_2\ \ \ \ \ \ \ \ c_3\ \ \ \ \ \ \ \ ... Cn3 c1 c2 c3 ...
. . . . . . . . . . . . ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ... ... ... ... ...
C n m 0 0 . . . C_n^m\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ ... Cnm 0 0 ...
有如下性质:
- 序列的第 n n n项 a n a_n an为: a n = a 1 + b 1 C n − 1 1 + c 1 C n − 1 2 + . . . + 0 C n − 1 m a_n = a_1 + b_1C_{n-1}^1 + c_1C_{n-1}^2+...+0C_{n-1}^m an=a1+b1Cn−11+c1Cn−12+...+0Cn−1m
- 序列的前缀和 S n S_n Sn为: S n = a 1 C n 1 + b 1 C n 2 + c 1 C n 2 + . . . + 0 C n m S_n = a_1C_n^1 + b_1C_n^2 + c_1C_n^2 + ... + 0C_n^m Sn=a1Cn1+b1Cn2+c1Cn2+...+0Cnm
当然, a n a_n an也可以由 S n − S n − 1 S_n - S_{n-1} Sn−Sn−1得到
例如:
序列:1, 4, 9, 16, 25
C n 1 1 4 9 16 25 . . . C_{n}^1\ \ \ \ \ \ 1\ \ \ \ \ \ 4\ \ \ \ \ \ 9\ \ \ \ \ \ 16\ \ \ \ \ \ 25\ \ \ \ \ \ ... Cn1 1 4 9 16 25 ...
C n 2 3 5 7 9 . . . C_n^2 \ \ \ \ \ \ \ \ \ \ \ 3\ \ \ \ \ \ \ 5\ \ \ \ \ \ \ 7\ \ \ \ \ \ \ 9\ \ \ \ \ \ \ ... Cn2 3 5 7 9 ...
C n 3 2 2 2 . . . C_n^3\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 2\ \ \ \ \ \ \ \ 2\ \ \ \ \ \ \ \ 2\ \ \ \ \ \ \ \ ... Cn3 2 2 2 ...
. . . . . . . . . . . . ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ...\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ... ... ... ... ...
C n m 0 0 . . . C_n^m\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ ... Cnm 0 0 ...
那么有:
a n = 1 + 3 C n − 1 1 + 2 C n − 1 2 = n 2 a_n = 1 + 3C_{n-1}^1 + 2C_{n-1}^2 = n^2 an=1+3Cn−11+2Cn−12=n2
S n = C n 1 + 3 C n 2 + 2 C n 3 = n ( n + 1 ) ( 2 n + 1 ) 6 S_n = C_n^1 + 3C_n^2 + 2C_n^3 = \frac{n(n+1)(2n+1)}{6} Sn=Cn1+3Cn2+2Cn3=6n(n+1)(2n+1)
2.2.2 高斯消元法
对于一个 r r r阶高次等差数列,我们可以设其有一个对应的多项式: f ( x ) = a ∗ x r + b ∗ x r − 1 + c ∗ x r − 2 + . . . + t f(x) = a*x^r + b*x^{r - 1} + c * x^{r-2}+...+t f(x)=a∗xr+b∗xr−1+c∗xr−2+...+t,然后带入 r + 1 r + 1 r+1个点,即可得到 r + 1 r+1 r+1个方程,通过高斯消元解方程,即可得到所有的系数 a 、 b 、 c 、 . . . a、b、c、... a、b、c、...,从而得到多项式的方程。
例如数列:1, 5, 15, 35, 70, 126, 210。
进行差分可以得到:
2.2.3 拉格朗日插值法
可以直接带入拉格朗日插值法公式:
f ( x ) = ∑ i = 1 n y i ∏ j ≠ i x − x j x i − x j f(x)=\sum_{i=1}^{n} y_i\prod_{j\neq i }\frac{x-x_j}{x_i-x_j} f(x)=∑i=1nyi∏j=ixi−xjx−xj
从而得到特定点的 f ( k ) f(k) f(k):
f ( k ) = ∑ i = 1 n y i ∏ j ≠ i k − x j x i − x j f(k)=\sum_{i=1}^{n} y_i\prod_{j\neq i }\frac{k-x_j}{x_i-x_j} f(k)=∑i=1nyi∏j=ixi−xjk−xj
2.3 暴力线性递推方程
对于一些数列,它可能和前面的几项数列都有关系,可能是线性递推式子,例如 f ( i ) = a f ( i − 1 ) + b f ( i − 2 ) + c f ( i − 3 ) + . . . + t f(i) = af(i - 1) + bf(i - 2) + cf(i - 3) + ... + t f(i)=af(i−1)+bf(i−2)+cf(i−3)+...+t,那么可以暴力枚举所有的系数,一般来说,我们设 f [ i ] = a ∗ f [ i − 3 ] + b ∗ f [ i − 2 ] + c ∗ f [ i − 1 ] + d f[i] = a * f[i - 3] + b * f[i - 2] + c * f[i - 1] + d f[i]=a∗f[i−3]+b∗f[i−2]+c∗f[i−1]+d, 如果不够再增加长度。
例如:icpc 2017 南宁区域赛L. Twice Equation
得到数列:0 3 20 119 696 4059 23660 137903 803760 4684659 27304196 159140519。使用暴力枚举线性递推的系数,系数从-100枚举到100,暴力代码如下:
#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
typedef long long LL;
int n, T, m;
int main() {
for (int a = -100; a <= 100; ++a) {
for (int b = -100; b <= 100; ++b) {
for (int c = -100; c <=100; ++c) {
for (int d = -100; d <= 100; ++d) {
// 0 3 20 119 696 4059 23660 137903 803760 4684659 27304196 159140519
// f[i] = a * f[i - 3] + b * f[i - 2] + c * f[i - 1] + d
if (696 == 3 * a + 20 * b + 119 * c + d && 119 == 3 * b + 20 * c + d && 4059 == 20 * a + 119 * b + c * 696 + d && 23660 == 4059 * c + 696 * b + 119 * a + d) {
if (137903 == 696 * a + 4059 * b + 23660 * c + d)
if (803760 == 4059 * a + 23660 * b + 137903 * c + d)
if (4684659 == 803760 * c + 137903 * b + 23660 * a + d)
if (27304196 == 4684659 * c + 803760 * b + 137903 * a + d)
if (159140519 == 27304196 * c + 4684659 * b + 803760 * a + d)
cout << a << " " << b << " " << c << " " << d << endl;
}
}
}
}
}
return 0;
}
打出来一个式子的系数为:0 -1 6 2(当然其他的系数也可以,比如:1 -7 7 0),所对应的式子是: f [ i ] = 6 ∗ f [ i − 1 ] − f [ i − 2 ] + 2 f[i] = 6 * f[i - 1] - f[i - 2] + 2 f[i]=6∗f[i−1]−f[i−2]+2(或者: f [ i ] = f [ i − 3 ] − 7 f [ i − 2 ] + 7 f [ i − 1 ] f[i] = f[i - 3] - 7f[i - 2] + 7f[i - 1] f[i]=f[i−3]−7f[i−2]+7f[i−1])。