题目连接
Fib(N)表示斐波那契数列的第N项(F(0) = 0, F(1) = 1),给出N和K,求
∑i=1N[Fib(i) mod Fib(K)]
由于结果太大,输出Mod 1000000007的结果。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行2个数N, K(1 <= N, K <= 10^18)
Output
共T行:对应每一组数据的答案。
Input示例
2
5 5
13 5
Output示例
7
29
先引入 Fn 的负数概念:
按这个方法我们可以得到如下的值:
如此一来有
列出一些可能用到的公式:
(Note:公式的证明和更多相关的公式可以查看另一篇文章:)
接下来分析 Fm%Fk,1≤m≤n,
设 m=ik+j
由(1)式可得:
到这里就可以解决1365 Fib(N) mod Fib(K)
对于 ∑ni=1(Fn%Fk) 的结果,我们把 n每k个数分成一段,最后r 个数是一段,我们分析每一段例如: ∑k−1j=1(Fik−1Fj%Fk),0≤i<d
由(3)式,我们有对 k 进行奇偶分类讨论会方便很多。
另外由(3)式可以知道 Fik%Fk=0 ,所以可以忽略所有k的倍数下标的数。
这么一来,如果 r=k−1 的话,可以直接让d加一, r 变为0.
注意要记录 Fm%Fk 负数的的个数,因为每一个负数都要加上 Fk .
算 Fk 用快速幂就可以,所有计算可以在mod=1e9+7下进行。问题完全解决了。
code:
#include<stdio.h>
#include<string.h>
#define LL long long
#define REP(i,a,b) for(int i=a;i<b;++i)
const int N = 2;
const int mod = 1000000007;
struct M
{
LL a[N][N];
M(int v = 0)
{
memset(a, 0, sizeof a);
REP(i, 0, N) a[i][i] = v;
}
M operator *(const M& b) const
{
M ret;
REP(i, 0, N)
REP(j, 0, N)
REP(k, 0, N)
{
ret.a[i][j] += a[i][k] * b.a[k][j];
ret.a[i][j] %= mod;
}
return ret;
}
M power(LL b) const
{
M ret = 1, a = *this;
while (b)
{
if (b & 1) ret = ret*a;
b >>= 1;
a = a*a;
}
return ret;
}
};
LL getf(LL n)
{
if (n == 0) return 0;
M I;
I.a[0][0] = I.a[0][1] = I.a[1][0] = 1;
I.a[1][1] = 0;
I = I.power(n - 1);
return I.a[0][0] % mod;
}
int main()
{
LL n, k;
int t;
scanf("%d", &t);
LL ans;
while (t--)
{
ans = 0;
scanf("%lld%lld", &n, &k);
if (k <= 2)
{
puts("0");
continue;
}
LL d = n / k;
LL r = n%k;
if (r == k - 1) { d++; r = 0; }
LL cntf = 0;
if (k % 2)
{
cntf = ((d + 1) / 4%mod) * ((k - 1)%mod)%mod + (d / 2%mod) * ((k - 1) / 2%mod)%mod;
if (d % 4 == 1 || d % 4 == 2) ans += getf(k + 1) - 1;
ans %= mod;
if (d % 4 == 2 || d % 4 == 3) ans += getf(k - 2) - 1;
ans %= mod;
if (r)
{
if (d % 2)
{
LL tmp = getf(k - 2);
if (r % 2) tmp = (tmp + getf(k - r - 2)) % mod;
else tmp = (tmp - getf(k - r - 2)) % mod;
if (((d - 1)/2) % 2) ans -= tmp;
else ans += tmp;
ans %= mod;
cntf += (r >> 1);
if (r % 2 && d % 4 == 3) cntf++;
}
else
{
LL tmp = getf(r + 2) - 1;
if ((d / 2) % 2) ans -= tmp;
else ans += tmp;
ans %= mod;
if (d % 4 == 2) cntf += r;
}
}
}
else
{
ans = ((d + 1) / 2) % mod*(getf(k + 1) - 1) % mod + (d / 2) % mod*(getf(k - 2) + 1);
cntf += (d / 2) % mod*((k - 1) / 2 % mod);
if (r)
{
if(d%2==0)
ans += getf(r + 2) - 1;
else
{
ans += getf(k - 2);
ans %= mod;
if (r % 2 == 0)
ans -= getf(k - r - 2);
else ans += getf(k - r - 2);
cntf += r / 2;
}
}
}
cntf %= mod;
ans += (cntf*getf(k)) % mod;
ans = (ans%mod + mod) % mod;
printf("%lld\n", ans);
}
}