Description
Fib(N)
表示斐波那契数列的第
N
项
Solution
先贴几个公式。
F−n=(−1)n−1Fn
Fn=FkFn−k+1+Fk−1Fn−k(1)
F2k−1+Fk−1Fk−F2k=(−1)k(2)
(2)
式可以考虑对
(1110)n=(Fn+1FnFnFn−1)
这个等式两边同时计算行列式。
Fn≡F⌊nk⌋k−1Fnmodk(modFk)
这就是考虑按
(1)
式展开就好了。设
i=⌊nk⌋,j=nmodk
所以
Fn≡Fik−1Fj(modFk)
这里需要分类讨论 i 的奇偶性:
若
Fik−1Fj==(F2k−1+Fk−1Fk−F2k)i2Fj(−1)i2kFj
若 i 为奇数,考虑将
Fik−1Fj====Fik−1(Fk−1Fj−k+FkFj−k+1)Fi+1k−1Fj−kFi+1k−1(−1)k−j−1Fk−j(−1)i+12k+k−j−1Fk−j
到这里就可以通过矩阵乘法快速幂得到答案啦!
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
typedef long long ll;
inline void Add(ll &x, ll b) {
x += b; while (x >= MOD) x -= MOD;
}
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
ll n, i, j, k, f, ans, fk;
int test;
struct Matrix {
ll a[3][3];
inline ll* operator [](ll x) {
return a[x];
}
inline Matrix(void) {
memset(a, 0, sizeof a);
}
inline friend Matrix operator *(Matrix a, Matrix b) {
Matrix x;
for (ll i = 1; i <= 2; i++)
for (ll j = 1; j <= 2; j++)
for (ll k = 1; k <= 2; k++)
Add(x[i][j], a[i][k] * b[k][j] % MOD);
return x;
}
};
Matrix Fib, I;
inline Matrix Pow(Matrix a, ll b) {
Matrix c = I;
while (b) {
if (b & 1) c = c * a;
b >>= 1; a = a * a;
}
return c;
}
inline ll F(ll x, ll y, ll z = 0) {
if ((x & 1) && (y & 1)) return z & 1 ? 1 : -1;
return z & 1 ? -1 : 1;
}
int main(void) {
freopen("1.in", "r", stdin);
I[1][1] = I[2][2] = 1;
Fib[1][1] = Fib[1][2] = Fib[2][1] = 1;
read(test);
while (test--) {
read(n); read(k);
i = n / k; j = n % k;
if (i & 1) {
if (k - j == k) f = 0;
else f = Pow(Fib, k - j)[1][2];
fk = Pow(Fib, k)[1][2];
ans = F((i + 1) / 2, k, k - j - 1) * f;
if (ans < 0) ans += fk;
Add(ans, MOD);
printf("%d\n", ans);
} else {
if (j == k) f = 0;
else f = Pow(Fib, j)[1][2];
ans = F(i / 2, k) * f;
fk = Pow(Fib, k)[1][2];
if (ans < 0) ans += fk;
Add(ans, MOD);
printf("%d\n", ans);
}
}
return 0;
}