题解-P4451 [国家集训队]整数的lqp拆分[*medium]
列出斐波那契数列的生成函数:\(G(x) = \frac{x}{1 - x - x^2}\)
答案的生成函数就是 \(\sum\limits_{i \ge 1} G(x)^i\)
\(F(x) = \sum\limits_{i \ge 1} G(x)^i = \frac{G(x)}{1 - G(x)} = \frac{\frac{x}{1 - x - x^2}}{1 - \frac{x}{1 - x - x^2}} = \frac{x}{1 - 2x - x^2}\)
\((1 - 2x - x^2) F(x) = x\),\(F(x) = 2 x F(x) + x^2 F(x) + x\)
得到递推柿 :\(f_1 = 1\),\(f_i = 2 f_{i - 1} + f_{i - 2}\)
这个可以矩乘,但是蒟蒻要介绍的是生成函数的方法。
\(F(x) = \frac{x}{1 - 2x - x^2}\)
因为 \(\frac{1}{1 - q \times x^k}\) 的第 \(t\) 项是很好算的,所以我们把他拆分成 \(\frac{a}{1 - x_1 x} + \frac{b}{1 - x_2 x}\) 的形式。
\(x_1, x_2\) 是 \(x^2 - 2x - 1\) 的两根。\(x_1 = 1 + \sqrt {2}, x_2 = 1 - \sqrt {2}\)
这是一次方程,解得 \(\begin{cases} a = \frac{1}{x_1 - x_2} \\ b = \frac{1}{x_2 - x_1} \end{cases}\)
那么得到了 \(F(x) = ( \frac{1}{x_1 - x_2} ) \frac{1}{1 - x_1 x} + ( \frac{1}{x_1 - x_2} ) \frac{1}{1 - x_2 x}\)
他的 \([x^n]\) 项就是 \(\frac{1}{x_1 - x_2} x_1^n + \frac{1}{x_2 - x_1} x_2^n = \frac{1}{x_1 - x_2} (x_1 ^ n - x_2 ^ n) = \frac{1}{2 \sqrt {2}} ( (1 + \sqrt{2})^n - (1 - \sqrt{2})^n)\)
\(\sqrt{2}\) 模 \(10^9 + 7\) 是 \(59713600\) 和 \(940286407\)。
于是费马小定理 + 快速幂就行了
#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define db double
#define mkp make_pair
using namespace std;
const int N = 3e5 + 7;
const int mod = 1e9 + 7;
const int sqrt2 = 59713600;
int read() {
int x = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while('0' <= ch && ch <= '9') x = ( (ll) x * 10 + (ch - '0') ) % (mod - 1), ch = getchar();
return x;
}
int n;
int qpow(int x, int y = mod - 2) {
int res = 1;
for(; y; x = (ll) x * x % mod, y >>= 1) if(y & 1) res = (ll) res * x % mod;
return res;
}
int main() {
n = read();
cout << (ll) qpow(2ll * sqrt2 % mod) * (qpow(1 + sqrt2, n) - qpow(1 - sqrt2 + mod, n) + mod) % mod << endl;
return 0;
}