Fibonacci数列

通项式: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)=0f(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]将杨辉三角依次下降,将同一行的数加起来,即得一数列112358......


题目:

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();
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值