知识点 -斐波拉契数和线性递推方程取模
解决问题类型:
斐波那契数列的各种性质
结论:
定义
(1)满足递推方程 F i = F i − 1 + F i − 2 , i ≥ 3 ; F 1 = F 2 = 1 F_{i} = F_{i - 1} + F_{i - 2},i \geq 3;F_{1} = F_{2} = 1 Fi=Fi−1+Fi−2,i≥3;F1=F2=1,的数列 { F n } \left\{ F_{n} \right\} {Fn}称为斐波那契数列, F n F_{n} Fn为斐波那契数。
(2)斐波那契数列的通项公式为 F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F_{n} = \frac{1}{\sqrt{5}}\left\lbrack \left( \frac{1 + \sqrt{5}}{2} \right)^{n} - \left( \frac{1 - \sqrt{5}}{2} \right)^{n} \right\rbrack Fn=51[(21+5)n−(21−5)n]
(3) F n ≡ 276601605 ( 69150401 3 n − 30849599 7 n ) ( m o d ( 1 0 9 + 9 ) ) F_n≡276601605(691504013^n-308495997^n)(mod\ (10^9+9)) Fn≡276601605(691504013n−308495997n)(mod (109+9))
性质
- Cassini’s 特征:
F n − 1 F n + 1 − F n 2 = ( − 1 ) n F_{n-1} F_{n+1} - F_n^2 = (-1)^n Fn−1Fn+1−Fn2=(−1)n - 加法规则:
F n + k = F k F n + 1 + F k − 1 F n F_{n+k} = F_k F_{n+1} + F_{k-1} F_n Fn+k=FkFn+1+Fk−1Fn - 加法规则推论:
F 2 n = F n ( F n + 1 + F n − 1 ) F_{2n} = F_n (F_{n+1} + F_{n-1}) F2n=Fn(Fn+1+Fn−1) - 用上面的结论加归纳法可以证明:对任意正整数 k k k, F n k F_{nk} Fnk 是 F n F_n Fn的倍数.
- 逆命题也正确: 如果 F m F_{m} Fm 是 F n F_n Fn的倍数,那么m是n的倍数。
- GCD 特征: G C D ( F m , F n ) = F G C D ( m , n ) GCD(F_m, F_n) = F_{GCD(m, n)} GCD(Fm,Fn)=FGCD(m,n)
- 斐波那契数列是欧几里得最差情况的输入
斐波那契编码
一个自然数可以被唯一地表示为斐波那契数的和
N
=
F
k
1
+
F
k
2
+
…
+
F
k
r
N = F_{k_1} + F_{k_2} + \ldots + F_{k_r}
N=Fk1+Fk2+…+Fkr
每次贪心地用最大的斐波那契数去减即可。
模p的循环节
对于递推式 x i = a ∗ x i − 1 + b ∗ x i − 2 x_i = a*x_{i-1}+b*x_{i-2} xi=a∗xi−1+b∗xi−2。
如果 c = a 2 + 4 b c=a^2+4b c=a2+4b是模 p p p的二次剩余,那么循环节的的长度是 p − 1 p-1 p−1的因子,否则,循环节的长度是 ( p + 1 ) ( p − 1 ) (p+1)(p-1) (p+1)(p−1)的因子。
模m的循环节
(1)把m素因子分解,即 m = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 . . . ∗ p n a n m = p_1^{a_1} * p_2^{a_2} * p_3^{a_3} ... * p_n^{a_n} m=p1a1∗p2a2∗p3a3...∗pnan
(2)分别计算Fib数模每个 p i a i p_i^{a_i} piai的循环节长度,假设长度分别是 l 1 , l 2 . . . l k l_1,l_2...l_k l1,l2...lk
(3)那么Fib模n的循环节长度 L = l c m ( l 1 , l 2 . . . l k ) L=lcm(l_1,l_2...l_k) L=lcm(l1,l2...lk)
算 p a p^a pa的循环节要用到定理: 令 G ( p ) G(p) G(p) 是 m o d p mod\ p mod p的最小循环节,则 G ( p a ) = G ( p ) ∗ p a − 1 G(p^a)= G(p) * p^{a-1} G(pa)=G(p)∗pa−1
十进制矩阵快速幂
解 M n M^n Mn, n < 1 e 6 n<1e6 n<1e6,M是2乘2的矩阵,时间复杂度为 O ( n ∗ l o g ( 10 ) ∗ k 3 ) O(n*log(10)*k^3) O(n∗log(10)∗k3), 注意1e6已经是上限。
想法是: a 123 = a 3 + a 2 ∗ 10 + a 3 ∗ 100 a^{123}=a^3+a^{2*10}+a^{3*100} a123=a3+a2∗10+a3∗100
int len = strlen(str);
for(int i = len-1;i >= 0;i --) {
int d = str[i]-'0';
if(d != 0) res = res*mat_pow_mod(base,d);
base = mat_pow_mod(base,10);
}
复杂度:
例题
给出 x 0 , x 1 , a , b , n , M O D x_0,x_1,a,b,n,MOD x0,x1,a,b,n,MOD 求解公式 x i = a ∗ x i − 1 + b ∗ x i − 2 x_i = a*x_{i-1}+b*x_{i-2} xi=a∗xi−1+b∗xi−2
数据范围: 1 ≤ x 0 , x 1 , a , b ≤ 1 0 9 1\le x_0 ,x_1,a,b\le 10^{9} 1≤x0,x1,a,b≤109 1 ≤ n ≤ 1 0 1 0 6 , 1 0 9 ≤ M O D ≤ 2 ∗ 1 0 9 1\le n \le 10^{10^6},10^9 \le MOD \le 2*10^9 1≤n≤10106,109≤MOD≤2∗109
代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static int moder;
public static class Matrix{
public static final int N = 2;
public int[][] a;
public Matrix(){a = new int[2][2];}
public Matrix multiply(Matrix p){
Matrix ret = new Matrix();
for (int i = 0; i < N; ++ i){
for (int k = 0; k < N; ++ k){
for (int j = 0; j < N; ++ j){
ret.a[i][j] = (int) ((ret.a[i][j] + 1L * a[i][k] * p.a[k][j]) % moder);
}
}
}
return ret;
}
}
public static void main(String[] args){
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
String nextLine = bufferedReader.readLine();
String[] splitted = nextLine.split(" ");
int x0 = Integer.parseInt(splitted[0]);
int x1 = Integer.parseInt(splitted[1]);
int a = Integer.parseInt(splitted[2]);
int b = Integer.parseInt(splitted[3]);
nextLine = bufferedReader.readLine();
splitted = nextLine.split(" ");
moder = Integer.parseInt(splitted[1]);
int x = moder;
BigInteger mod = BigInteger.ONE;
for (int i = 2; i * i <= x; ++ i){
if (x % i == 0){
while (x % i == 0){
mod = mod.multiply(BigInteger.valueOf(i));
x /= i;
}
mod = mod.multiply(BigInteger.valueOf(i - 1));
mod = mod.divide(BigInteger.valueOf(i));
mod = mod.multiply(BigInteger.valueOf(i + 1));
}
}
if (x > 1){
mod = mod.multiply(BigInteger.valueOf(x - 1));
mod = mod.multiply(BigInteger.valueOf(x + 1));
}
BigInteger n = BigInteger.ZERO;
for (int i = 0; i < splitted[0].length(); ++ i){
n = n.multiply(BigInteger.TEN).add(BigInteger.valueOf(splitted[0].charAt(i) - '0')).mod(mod);
}
n = n.add(mod);
Matrix aa = new Matrix();
Matrix ret = new Matrix();
aa.a[0][1] = 1;
aa.a[1][0] = b;
aa.a[1][1] = a;
ret.a[0][0] = ret.a[1][1] = 1;
for (int i = 0; i < 4000000; ++i) {
if (n.testBit(i)) {
ret = ret.multiply(aa);
}
aa = aa.multiply(aa);
}
Long ans = (1L * ret.a[0][0] * x0 + 1L * ret.a[0][1] * x1) % moder;
System.out.println(ans);
}
catch (IOException e){
e.printStackTrace();
}
}
}