@description@
B 君有两个好朋友,他们叫宁宁和冉冉。有一天,冉冉遇到了一个有趣的题目:输入 (b, d, n),求:
@solution@
这道题的思路最早可以追溯到这一道经典题目吧。。。
注意到数据范围满足 (b^2 le d < (b + 1)^2)(虽然样例不满足),这意味着 (|frac{b - sqrt{d}}{2}| < 1)。
利用共轭的性质。如果我们求出 (f(n) = (frac{b + sqrt{d}}{2})^n + (frac{b - sqrt{d}}{2})^n) 的整数部分,则题目所要的东西实际上 = f(n) 或 f(n) - 1。
尝试递推。看到分母除 2,想到二次方程的求根公式。
记 (p = (frac{b + sqrt{d}}{2}), q = (frac{b - sqrt{d}}{2})),则 p, q 应该为方程 (x^2 - bx + frac{b^2 - d}{4} = 0) 两根。
也就说有 (p^2 = bp - frac{b^2 - d}{4}, q^2 = bq - frac{b^2 - d}{4})
然后就可以带入 f(n) 的式子里面降次,得到 f(n) 与 f(n-1),f(n-2) 的递推式子。矩阵幂即可。
-------分割线--------
当然还有另一种看起来更nb的推导方法。
我们构造 f(n) 的生成函数,记 (F(x) = sum_{i=0}f(i)x^i)。则:
再对等式进行变形:
对应项系数比较,除 0 和 1 以外,有 (f(n) = -frac{b^2 - d}{4}f(n-2) + bf(n-1))。得到了一样的结果。
其实这就是斐波那契的通项公式的逆推导过程。
@accepted code@
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const ull MOD = 7528443412579576937LL;
ull add(ull A, ull B) {
return (A + B >= MOD ? A + B - MOD : A + B);
}
ull mul(ull A, ull B) {
ull C = 0;
for(ull i=B;i;i>>=1,A=add(A,A))
if( i & 1 ) C = add(C, A);
return C;
}
ull A[2][2], R[2][2], C[2][2];
void mul(ull B[][2]) {
C[0][0] = add(mul(B[0][0], A[0][0]), mul(B[0][1], A[1][0]));
C[0][1] = add(mul(B[0][0], A[0][1]), mul(B[0][1], A[1][1]));
C[1][0] = add(mul(B[1][0], A[0][0]), mul(B[1][1], A[1][0]));
C[1][1] = add(mul(B[1][0], A[0][1]), mul(B[1][1], A[1][1]));
B[0][0] = C[0][0], B[0][1] = C[0][1], B[1][0] = C[1][0], B[1][1] = C[1][1];
}
int main() {
ull b, d, n;
cin >> b >> d >> n;
A[0][0] = b, A[0][1] = (d - b*b) / 4;
A[1][0] = 1, A[1][1] = 0;
R[0][0] = R[1][1] = 1, R[1][0] = R[0][1] = 0;
for(ull i=n;i;i>>=1,mul(A))
if( i & 1 ) mul(R);
ull res = add(mul(b, R[1][0]), mul(2, R[1][1]));
if( n % 2 == 0 ) {
res = (res == 0 ? MOD - 1 : res - 1);
}
cout << res << endl;
}
@details@
有一个小疑问:照这样推导下来 (f(n) = (frac{b + sqrt{d}}{2})^n + (frac{b - sqrt{d}}{2})^n) 一定为整数。
可是为什么。可以证明这一点吗?