【训练题36:数学】斐波那契各项幂次前缀和
正题
- 【链接】
斐波那契各项幂次前缀和 - 【题意】给定
n
,
K
n,K
∑
i
=
1
n
(
F
i
b
i
)
K
(
m
o
d
1
e
9
+
9
)
\sum_{i=1}^n (Fib_i)^{K}\pmod {1e9+9}
其中F
i
b
i
Fib_i
i
i
F
i
b
[
]
=
[
1
,
1
,
2
,
3
,
5
,
8
,
⋯
]
Fib[]=[1,1,2,3,5,8,\cdots]
- 【范围】
1
≤
n
≤
1
0
18
1\le n\le 10^{18}
1
≤
K
≤
1
0
5
1\le K\le 10^5
解法
- 由于
K
K
具体内容见我的博客:【小组专题三:斐波那契专题】
f
n
=
1
5
(
α
n
−
β
n
)
f_n=\frac{1}{\sqrt 5}(\alpha^n-\beta^n)
其中α
=
5
+
1
2
,
β
=
5
−
1
2
\alpha=\frac{\sqrt5+1}{2},\beta=\frac{\sqrt5-1}{2}
于是,我们要求的内容就变成了:(以下式子皆省略模数)
∑
i
=
1
n
(
F
i
b
i
)
K
=
∑
i
=
1
n
1
5
K
(
α
i
−
β
i
)
K
=
1
5
K
∑
i
=
1
n
(
α
i
−
β
i
)
K
\sum_{i=1}^n (Fib_i)^{K}=\sum_{i=1}^n \frac{1}{\sqrt5^K}(\alpha^i-\beta^i)^K= \frac{1}{\sqrt5^K}\sum_{i=1}^n(\alpha^i-\beta^i)^K
设1
5
K
=
R
e
\frac{1}{\sqrt5^K}=Re
我们只要求后面的一个二项式即可。我们把二项式拆开来,得到:
F
i
b
n
=
R
e
(
(
−
1
)
0
C
K
0
α
K
n
β
0
n
+
(
−
1
)
1
C
K
1
α
(
K
−
1
)
n
β
1
⋅
n
+
⋯
)
Fib_n=Re\Big( (-1)^0C_K^0 \alpha^{Kn}\beta^{0n} + (-1)^1C_K^1 \alpha^{(K-1)n}\beta^{1\cdot n} +\cdots\Big)
考虑到第i
i
(
−
1
)
i
C
K
i
α
(
K
−
i
)
n
β
i
⋅
n
(-1)^iC_K^i\alpha^{(K-i)n}\beta^{i\cdot n}
考虑到每一个n
n
α
(
K
−
i
)
β
i
\alpha^{(K-i)}\beta^i
问题一 :根号五?
- 【Q】考虑到需要多次计算出
5
\sqrt5
- 【A】就是二次剩余的知识,见我的博客 【算法讲18:二次剩余】
用c
i
p
o
l
l
a
cipolla
5
\sqrt5
问题二 :公比模意义为一?
- 【Q】根据等比求和,公比必须不为
1
1
α
(
K
−
i
)
β
i
\alpha^{(K-i)}\beta^i
1
1
- 【A】如果公比为
1
1
R
e
×
(
−
1
)
i
×
n
Re\times (-1)^i\times n
核心代码
- 时间复杂度:
O
(
K
log
K
)
O(K\log K)
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/
const ll sq5 = 383008016;
const ll iv2 = inv(2);
ll fac[MAX],ivfac[MAX];
ll C(int n,int m){
if(m < 0 || m > n)return 0;
return fac[n] * ivfac[m] % MOD * ivfac[n - m] % MOD;
}
void init(int n){
fac[0] = 1;
for(int i = 1;i <= n;++i){
fac[i] = fac[i-1] * i % MOD;
}
ivfac[n] = inv(fac[n]);
for(int i = n - 1;i >= 0;--i){
ivfac[i] = ivfac[i+1] * (i + 1) % MOD;
}
}
int main()
{
init((int)1e5);
int T;scanf("%d",&T);
while(T--){
ll n,k;
scanf("%lld%lld",&n,&k);
ll xi = inv(qpow(sq5,k));
ll alpha = (1LL + sq5) * iv2 % MOD;
ll beta = (1LL - sq5 + MOD) * iv2 % MOD;
ll res = 0;
for(int i = 0;i <= k;++i){
ll tmp = C(k,i);
if(i & 1)tmp = (-tmp + MOD) % MOD;
ll shu = qpow(alpha,k-i) * qpow(beta,i) % MOD;
ll shu2= qpow(shu,n);
if(shu == 1){ /// 公比为 1
res = (res + n % MOD * tmp % MOD) % MOD;
continue;
} /// 等比数列求和公式
tmp = tmp * shu % MOD * (shu2 - 1) % MOD * inv(shu - 1) % MOD;
res = (res + tmp) % MOD;
}
res = res * xi % MOD;
res = (res + MOD) % MOD;
printf("%lld\n",res);
}
return 0;
}