通项式:F(n) = (((1+Sqrt(5))/2)^n – ((1-Sqrt(5))/2)^n)*1/Sqrt(5)
递推式:F0 = 0, F1 = 1, and Fn = F(n − 1) + F(n − 2)
[定理1]标准Fibonacci序列(即f(0)=0,f(1)=1)当N大于1时,一定有f(N)和f(N-1)互质
[定理2]若i为奇数, f(i)*f(i)=f(i-1)*f(i+1)+1,否则f(i)*f(i)=f(i-1)*f(i+1)-1
[定理3]f(n)=f(i)*f(n-i-1)+f(i+1)*f(n-i) 用来计算较大的fibonacci数除以某个数的余数
[定理4] 当i较大时,f(i)≈((1+Sqrt(5))/2)^n/sqrt(5);
[定理5] 标准Fibonacci序列对任意大于2的正整数的余数序列,必然是以“0 1”为循环节开头的序列;(满足线性齐次递推式的数列都有循环节?)
证明方法是利用同余定理、反证法,还有我们之前证明过的相邻项一定互质的定理。
[应用1]斐波那契数列的第n项同代表了集合{1,2,...,n}中所有不包含相邻正整数的子集个数。
[应用2]将杨辉三角依次下降,将同一行的数加起来,即得一数列1、1、2、3、5、8......
题目:
1.hdu 1568 Fibonacci
题意:求斐波那契数列第n项的前四位,n<=10^8
解法:n小于40时直接计算,n大于40时利用约等式计算,利用换底公式保持精度。
double temp=(1.0+Math.sqrt(5))/2;
int work(int n){
if(n<40&&f[n]<10000)
return f[n];
double res=Math.log10(temp)*n-0.5*Math.log10(5.0);
res-=Math.floor(res);
res=Math.pow(10.0,res);
while(res<1000.0)
res*=10;
return (int)res;
}
2.hdu 4099 Revenge of Fibonacci
解法:11年上海现场赛I题,果然是场很坑的题,要求100000以内斐波那契数列中以x(最多40位)开头的最小元素,显然用trie树维护便可,但是与上题不同的是无法维护40位的精度,因此要用BigInteger维护前60位,这样可以保证前40位正确性。但是hdu没改虚拟机内存限制,因此只能用c++自写了个大数加法(re还不显示,一直以为是wa,搞了一晚上,苦逼)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
using namespace std;
struct BigInteger {
char val[110];
int len;
BigInteger() {
len = 0;
}
BigInteger add(BigInteger oth) {
int n = min(oth.len, len);
bool flag = false;
BigInteger res;
res.len = max(len, oth.len) + 1;
for (int i = 0; i < n; i++) {
int temp = val[len - i] - '0';
temp += oth.val[oth.len - i] - '0';
if (flag) {
temp++;
flag = false;
}
if (temp > 9)
flag = true;
temp %= 10;
res.val[res.len - i] = '0' + temp;
}
for (int i = n; i < len; i++) {
int temp = val[len - i] - '0';
if (flag) {
temp++;
flag = false;
}
if (temp > 9)
flag = true;
temp %= 10;
res.val[res.len - i] = temp + '0';
}
for (int i = n; i < oth.len; i++) {
int temp = oth.val[len - i] - '0';
if (flag) {
temp++;
flag = false;
}
if (temp > 9)
flag = true;
temp %= 10;
res.val[res.len - i] = temp + '0';
}
if (flag)
res.val[1] = '1';
else {
for (int i = 1; i < res.len; i++)
res.val[i] = res.val[i + 1];
res.len--;
}
return res;
}
};
struct Nod { //0为无效值
int lnk[10], val;
void init() {
memset(lnk, 0, sizeof(lnk));
val = -1;
}
};
const char BASE = '0';
struct Trie {
Nod buf[4000010];
int len;
void init() {
buf[len=0].init();
}
void insert(BigInteger str, int val) {
int now = 0;
for (int i = 1; i<=str.len&&i<=40;i++) {
int &nxt = buf[now].lnk[str.val[i] - BASE];
if (!nxt)
buf[nxt=++len].init();
now = nxt;
if (buf[now].val == -1)
buf[now].val = val;
}
}
int search(char* str) {
int now = 0;
for (int i = 0; str[i]; i++) {
int & nxt = buf[now].lnk[str[i] - BASE];
if (!nxt)
return -1;
now = nxt;
}
return buf[now].val;
}
} tree;
void build() {
tree.init();
BigInteger pre, ppre, now;
pre.len = ppre.len = 1;
pre.val[1] = ppre.val[1] = '1';
tree.insert(pre, 0);
for (int i = 2; i<100000; i++) {
now = pre.add(ppre);
ppre = pre;
pre = now;
if (now.len > 60) {
pre.len--;
ppre.len--;
}
tree.insert(now, i);
}
}
int main() {
build();
int cas;
char ch[50];
scanf("%d", &cas);
for (int k = 1; k <= cas; k++) {
scanf("%s", ch);
printf("Case #%d: %d\n", k, tree.search(ch));
}
return 0;
}
hdu 1021 Fibonacci Again
题意:讯问斐波那契数列第n为是否能被3整除。
做法:利用定理五找循环节
hdu 4291 A Short Problem
题意:已知g(n) = 3g(n - 1) + g(n - 2),求g(g(g(n))) mod 109 + 7。
做法:由定理五知,每层都存在循环节,因此只需在本地暴力找出每层的循环节即可。
最后找到的三层的循环节分别为183120, 222222224, 1000000007
hdu 1588 Gauss Fibonacci
题意:求斐波那契的等差数列项的和。
做法:g(i)是等差数列可知f(g(i))是等比数列,根据等比数列性质求矩阵1--n次幂的和。
import java.util.Scanner;
public class Main{
int mod, n = 2;
long[][] multy(long[][] a, long[][] b) {
long res[][] = new long[n + 1][n + 1];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
res[i][j]=(res[i][j]+(a[i][k]*b[k][j])%mod) % mod;
return res;
}
long[][] add(long[][] a, long[][] b) {
long res[][] = new long[n + 1][n + 1];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
res[i][j] = (a[i][j] + b[i][j]) % mod;
return res;
}
long[][] fastpow(long[][] mat, int p) {
if (p == 0)
return one;
if (p == 1)
return mat;
long temp[][] = fastpow(mat,p/2);
long res[][] = multy(temp, temp);
if (p % 2 == 1)
res = multy(res,mat);
return res;
}
long[][] getsum(long[][] mat, int k) {
if (k == 1)
return mat;
long[][] res = multy(getsum(mat, k/2), add(one,fastpow(mat,k/2)));
if (k % 2 == 1)
res = add(res, fastpow(mat, k));
return res;
}
long one[][], A[][];
void init(int n) {
this.n = n;
one = new long[n + 1][n + 1];
A = new long[n + 1][n + 1];
A[1][2] = A[2][1] = A[2][2] = 1;
one[1][1]=one[2][2]=1;
}
Scanner scan = new Scanner(System.in);
void run() {
init(2);
while (scan.hasNext()) {
int k = scan.nextInt();
int b = scan.nextInt();
int n = scan.nextInt();
mod = scan.nextInt();
long ab[][] = fastpow(A, b);
long ak[][] = fastpow(A, k);
long ans[][] = add(one, getsum(ak,n-1));
ans = multy(ab, ans);
System.out.println(ans[2][1]);
}
}
public static void main(String[] args) {
new Main().run();
}
}