codeforces193E.Fibonacci Number

6 篇文章 0 订阅

http://codeforces.com/problemset/problem/193/E

题意,给出一个n(0 <= n < 10^13), 问第一个模10^13后为n的Fibonacci数是多少,Fibonacci数就是0,1,1,2,3,5就是说第一个是0,第二个是1,然后后面每一个数是前两个的和。

思路:枚举发现Fibonacci最后一位数的循环节长为60,自然而然会觉得后两位循环节长肯定是60的倍数,后三位循环节长肯定是后两位的倍数,那么就可以一次求上去。枚举到7位后循环节长为1.5*10^7,13位的循环节长是1.5*10^13次方。

为什么要提到7位,我的做法就是枚举前1.5*10^7个Fibonacci数,如果后7位跟n的后7为相等,那么继续枚举的时候就可以每1.5*10^7一步。因为后7位跟n的后7相等的数的个数有限,所以时间复杂度应该不会太大。

#include <set>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;

#define sqr(x) ((x) * (x))
#define two(x) (1 << (x))
#define order(x, y, z) ((x) <= (y) && (y) <= (z))
#define X first
#define Y second

typedef long long LL;
typedef pair<LL, int> pli;

const int N = 1;
const double eps = 1e-7;
const int ten = 10000000;
const int oo = 1000000000;
const int base = 1000000000;
const LL f = 10000000000000LL;

struct Integer {
	LL a, b, c;
	Integer(LL x = 0): a(0), b(x / base), c(x % base) {}
};

LL fib[15][3];
LL cycle[15];

Integer operator * (Integer a, Integer b) {
	Integer product;
	product.c = a.c * b.c;
	product.b = a.b * b.c + a.c * b.b + product.c / base;
	product.a = a.a * b.c + a.b * b.b + a.c * b.a + product.b / base;
	product.c %= base;
	product.b %= base;
	product.a %= base;
	return product;
}

Integer operator + (Integer a, Integer b) {
	Integer sum;
	sum.c = a.c + b.c;
	sum.b = a.b + b.b + sum.c / base;
	sum.a = a.a + b.a + sum.b / base;
	sum.c %= base;
	sum.b %= base;
	sum.a %= base;
	return sum;
}

Integer operator % (Integer a, LL b) {
	Integer reminder;
	reminder.a = 0;
	if (b / base > 1) { 
		reminder.b = a.b % (b / base);
	} else {
		reminder.b = 0;
	}
	if (b > base) {
		reminder.c = a.c;
	} else {
		reminder.c = b;
	}
	return reminder;
}

bool operator != (Integer a, LL b) {
	return a.a != 0 || a.b != b / base || a.c != b % base;
}

LL mult(LL a, LL b, LL md) {
	LL ret = 0;
	for (; b; b >>= 1) {
		if (b & 1) {
			ret = (ret + a) % md;
		}
		a = (a + a) % md;
	}
	return ret;
}

LL getfib(LL n, LL md) {
	n = n - 1;
	LL base[2][2] = {{1, 1}, {1, 0}};
	LL mat[2][2] = {{1, 0}, {0, 1}};
	for (; n; n >>= 1) {
		if (n & 1) {
			LL temp[2][2] = {{mat[0][0], mat[0][1]}, {mat[1][0], mat[1][1]}};
			mat[0][0] = (mult(temp[0][0], base[0][0], md) + mult(temp[0][1], base[1][0], md)) % md;
			mat[0][1] = (mult(temp[0][0], base[0][1], md) + mult(temp[0][1], base[1][1], md)) % md;
			mat[1][0] = (mult(temp[1][0], base[0][0], md) + mult(temp[1][1], base[1][0], md)) % md;
			mat[1][1] = (mult(temp[1][0], base[0][1], md) + mult(temp[1][1], base[1][1], md)) % md;
		}
		LL temp[2][2] = {{base[0][0], base[0][1]}, {base[1][0], base[1][1]}};
		base[0][0] = (mult(temp[0][0], temp[0][0], md) + mult(temp[0][1], temp[1][0], md)) % md;
		base[0][1] = (mult(temp[0][0], temp[0][1], md) + mult(temp[0][1], temp[1][1], md)) % md;
		base[1][0] = (mult(temp[1][0], temp[0][0], md) + mult(temp[1][1], temp[1][0], md)) % md;
		base[1][1] = (mult(temp[1][0], temp[0][1], md) + mult(temp[1][1], temp[1][1], md)) % md;
	}
	return mat[0][0];
}

void init() {
	cycle[0] = 1;
	cycle[1] = 60;
	LL pt = 100;
	for (int i = 2; i <= 13; ++i) {
		cycle[i] = cycle[i - 1];
		LL x = getfib(cycle[i - 1] + 1, pt), y = getfib(cycle[i - 1], pt), z = getfib(cycle[i - 1] - 1, pt);
		LL f0 = y, f1 = x;
		while (f0 != 0 || f1 != 1) {
			LL nf1 = (mult(f1, x, pt) + mult(f0, y, pt)) % pt;
			LL nf0 = (mult(f1, y, pt) + mult(f0, z, pt)) % pt;
			f1 = nf1;
			f0 = nf0;
			cycle[i] += cycle[i - 1];
		}
		pt *= 10;
	}
	for (int i = 1; i <= 13; ++i) {
		fib[i][0] = getfib(cycle[i] - 1, f);
		fib[i][1] = getfib(cycle[i], f);
		fib[i][2] = getfib(cycle[i] + 1, f);
	}
}

void print(Integer a) {
	if (a.a == 0) {
		if (a.b == 0) {
			cout << a.c << endl;
		} else {
			cout << a.b;
			stringstream s;
			s << a.c;
			string ss = s.str();
			cout << string(9 - ss.size(), '0') << ss << endl;
		}
	} else {
		cout << a.a;
		stringstream sb, sc;
		sb << a.b;
		sc << a.c;
		string ssb = sb.str();
		string ssc = sc.str();
		cout << string(9 - ssb.size(), '0') << ssb << string(9 - ssc.size(), '0') << ssc << endl;
	}
}

int main() {
	init();
	LL n;
	cin >> n;
	if (n == 0) {
		cout << 0 << endl;
	} else if (n == 1) {
		cout << 1 << endl;
	} else {
		LL t = 3, a0 = 1, a1 = 2, a2 = 1;
		LL ans = (LL)oo * oo;
		while (t <= cycle[7] && t <= ans) {
			a2 = (a1 + a0) % ten;
			a0 = a1;
			a1 = a2;
			++t;
			if (a2 % ten == n % ten) {
				int d = 1;
				LL ac = t;
				Integer x(fib[7][2]), y(fib[7][1]), z(fib[7][0]);
				Integer f0(getfib(t - 1, f)), f1(getfib(t, f));
				while (f1 != n && d <= 1000000 && ac < ans) {
					Integer nf1((f1 * x + f0 * y) % f);
					Integer nf0((f1 * y + f0 * z) % f);
					f1 = nf1;
					f0 = nf0;
					ac += cycle[7];
					d++;
				}
				if (!(f1 != n)) {
					ans = min(ans, ac);
				}
			}
		}
		if (ans >= (LL)oo * oo) {
			cout << -1 << endl;
		} else {
			cout << ans << endl;
		}
	}
	return 0;
}

后来在某人的提点下发现从最低位逐位求上去就可以了。

新的代码,用python写的,时间比G++的还快了一倍。上面那个方法太搓了……

#! /usr/bin/env python
#  @author: grastyele

import copy

def fib(x, Mod):
	x = x - 1
	base = [[1, 1], [1, 0]]
	ret  = [[1, 0], [0, 1]]
	while x > 0:
		if x & 1:
			temp = copy.deepcopy(ret)
			for i in range(0, 2):
				for j in range(0, 2):
					ret[i][j] = 0
					for k in range(0, 2):
						ret[i][j] = (ret[i][j] + base[i][k] * temp[k][j]) % Mod
		temp = copy.deepcopy(base)
		for i in range(0, 2):
			for j in range(0, 2):
				base[i][j] = 0
				for k in range(0, 2):
					base[i][j] = (base[i][j] + temp[i][k] * temp[k][j]) % Mod
		x = x / 2
	return ret[0][0]

def count_cycle():
	size = [1, 60]
	Mod = 10
	for i in range(2, 14):
		Mod = Mod * 10
		x = fib(size[i - 1] - 1, Mod)
		f0 = y = fib(size[i - 1], Mod)
		f1 = z = (x + y) % Mod
		size.append(size[i - 1])
		while f0 != 0 or f1 != 1:
			f1, f0 = (z * f1 + y * f0) % Mod, (y * f1 + x * f0) % Mod
			size[i] += size[i - 1]
	return size

def solve(f, size):
	Mod = 10
	f0 = 0
	f1 = 1
	ans = []
	if f % 10 == 0:
		ans.append(0)
	elif f % 10 == 1:
		ans.append(1)
	for i in range(2, size[1]):
		f1, f0 = (f0 + f1) % 10, f1
		if f1 == f % 10:
			ans.append(i)
	for i in range(2, 14):
		Mod = Mod * 10
		for x in ans:
			if x + size[i - 1] < size[i]:
				ans.append(x + size[i - 1])
		temp = []
		for x in ans:
			if fib(x, Mod) == f % Mod:
				temp.append(x)
		ans = copy.deepcopy(temp)
	return min(ans) if len(ans) > 0 else -1

if __name__ == "__main__":
	size = count_cycle()
	print solve(int(raw_input()), size)


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值