Luogu P4451 [国家集训队]整数的lqp拆分

题目描述

https://www.luogu.com.cn/problem/P4451

简要题意:令 fn 为斐波那契数第 n 项,求 i=1mfaim>0,a1,a2,,am>0,i=1mai=n

n10100000

Solution

F(x) 为斐波那契数的生成函数,那么容易得到答案的生成函数就是 i=0F(x)i[n=0]=11F(x)[n=0]

我们考虑 G(x)=11F(x) 这个生成函数,我们知道 F(x)=x1xx2,那么 G(x)=1xx212xx2,我们尝试求出它的递推式

我们知道分母的递推式就是 an=2an1+an2,我们将这个递推式乘上 1xx2,那么变成 anan1an2=an1an=2an1+an2,解特征方程能得到 x1=12,x2=1+2,我们知道 a0=0,a1=1,能够得到 an=(1+2)n(12)n22

我们知道 21e9+7 下有二次剩余 59713600,那么我们直接做快速幂即可,注意指数要对 φ(1e9+7) 取模

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstring>
#define maxn 100010
#define ll long long
using namespace std;

const int p = 1000000007;
const int pp = 1000000006;
const int sqrt2 = 59713600;

ll pow_mod(ll x, ll n) {
ll s = 1;
for (; n; n >>= 1, x = x * x % p)
if (n & 1) s = s * x % p;
return s;
}

int n;
char s[maxn];

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> s + 1; n = strlen(s + 1); int k = 0;
for (int i = 1; i <= n; ++i) k = (10ll * k + s[i] - '0') % pp;
ll ans = (pow_mod(1 + sqrt2, k) - pow_mod(1 - sqrt2, k)) * pow_mod(2 * sqrt2, p - 2) % p;
cout << (ans + p) % p << "\n";
return 0;
}