由hdu多校自闭场衍生出的几题
题目1
求$$sum_{I = 1}^nF_i^k (mod 10^9 + 9)$$
感觉像是矩阵快速幂,其实不是
(F_{n} = frac{(frac{1+sqrt5}{2})^n- (frac{1-sqrt 5}{2})^n}{sqrt 5})
因为(383008016^2 equiv 5(mod 10^9 + 9))
所以(383008016 equiv sqrt 5(mod 10^9+9))
所以把383008016乘以(inv(5, 10^9+9))得到
(frac{sqrt 5}{5} equiv 276601605(mod 10^9+9))
同理
(frac{1 + sqrt 5}{5}equiv 691504013 (mod 10^9+9))
(frac{1 - sqrt 5}{5} equiv 308495997(mod 10^9 + 9))
那么(F_n = 276601605(691504013 ^ n - 308495997 ^ n) ( mod 10^9 + 9))
设(S = frac{sqrt 5}{5}, R_1 = frac{1 + sqrt5}{2}, R_2 = frac{1 - sqrt 5}{2})
那么(F_n^m = S^m(R_1^n - R_2^n)^m)
(F_n^m = S^msum_{k = 0} ^m C_m^k(R_1^{nk}R_2^{n(m - k)} * (-1)^{m - k}))
那么对于斐波那契前n项和为(S^msum_{k =0 } ^m[C_m^k(sum_{j = 1}^nR_1^{jk}R_2^{j(m - k)})*(-1)^{m - k}])
注意,如果说mod是其他的值,那么久需要用二次剩余求出该模下5的一个剩余
得到答案后,只需要线性递推出(C(m, i))在mod下的值,以及遍历最外面的循环k,其中内部的小循环是一个等比数列,直接快速幂求即可
时间复杂度(O(mlogn))
在求等比数列前n项时不能直接用求和公式(frac{a_1(q - q^n)}{1 - q}),因为q可能为1
整理一下
(F_{n} = frac{(frac{1+sqrt5}{2})^n- (frac{1-sqrt 5}{2})^n}{sqrt 5})
(F_n^m = (frac{1}{sqrt5})^m[(frac{1+sqrt5}{2})^n - (frac{1 - sqrt5}{2})^n]^m)
令(a = (frac{1+sqrt5}{2}),b = (frac{1-sqrt5}{2}))
那么(F_n^m = (frac{1}{sqrt5})^m[a^n - b^n]^m)
二项式展开
(F_n^m = (frac{1}{sqrt5})^msum_{k = 0}^m(-1)^kleft(egin{array}{c} m\kend{array} ight)(a^{m - k}b^k)^n)
令(t_k = a^{m - k}b^k)
那么(F_n^m = (frac{1}{sqrt5})^msum_{k = 0}^m(-1)^k left(egin{array}{c} m\kend{array} ight)t_k^n)
那么(sum_{i = 1}^nF_i^m = (frac{1}{sqrt 5})^msum_{k = 0}^m(-1)^kleft(egin{array}{c} m\kend{array} ight)sum_{i = 1}^nt_k^i)
在(mod 10^9+9)情况下,(a equiv 691504013 (mod 10^9+9), bequiv 308495997(mod 10^9 + 9), frac{1}{sqrt5}equiv 276601605(mod 10^9+9))
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int mod = 1e9 + 9;
const int N = 3e5 + 5;
ll S = 723398404, R1 = 308495997, R2 = 691504013;
ll F[N], a[N];
ll pow(ll a, ll b, ll p){
ll ans = 1; a %= p;
while(b){
if(b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y){
if(!b) {
d = a, x = 1, y = 0;
return;
}
ex_gcd(b, a % b, d, y, x);
y -= x * (a / b);
}
ll cal(ll a, ll b){ //等比数列前n项和
if(a == 1) return b % mod;
ll ans = pow(a, b + 1, mod);
ans = (ans - a + mod) % mod;
return ans * pow(a - 1, mod - 2, mod) % mod;
}
ll c[N];
int main(){
int t;
scanf("%d", &t);
while(t--) {
ll ans = 0;
ll n, m;
c[0] = 1;
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= m; i++) {// 线性求C(m, i)
ll d, x, y;
ex_gcd(i, mod, d, x, y); // 求i对mod的逆元
x = (x % mod + mod) % mod;
c[i] = (c[i - 1] * x) % mod;
c[i] = (c[i] * (m - i + 1)) % mod;
}
for(int i = 0; i <= m; i++) {
ll x = c[i];
x = x * cal(pow(R1, i, mod) * pow(R2, m - i, mod) % mod, n) % mod;
x = (x % mod + mod) % mod;
if((m - i) % 2) ans = (ans - x + mod) % mod;
else ans = (ans + x + mod) % mod;
}
ans = ans * pow(S, m, mod) % mod;
printf("%lld
", ans);
}
return 0;
}