1005 Fibonacci Sum
题意:
给定N、C(
1
0
18
10^{18}
1018)、K
(
1
0
5
)
(10^5)
(105)对于Fibonacci数列进行
F
0
K
+
F
C
K
+
F
2
C
K
+
.
.
.
+
F
N
C
K
F_0^{K}+F_C^{K}+F_{2C}^{K}+...+F_{NC}^{K}
F0K+FCK+F2CK+...+FNCK进行mod
(
1
0
9
+
9
)
(10^9+9)
(109+9)的计算
思路:
已知Fibonacci数列有个通项公式:
F
n
=
1
5
[
(
1
+
5
2
)
n
−
(
1
−
5
2
)
n
]
F_n=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]
Fn=51[(21+5)n−(21−5)n]
设
s
q
5
=
1
5
,
a
=
1
+
5
2
,
b
=
1
−
5
2
sq5=\frac{1}{\sqrt5},a=\frac{1+\sqrt5}{2},b=\frac{1-\sqrt5}{2}
sq5=51,a=21+5,b=21−5(程序计算得到
s
q
5
=
383008016
sq5=383008016
sq5=383008016)
- 代入通项公式 ⇒ s q 5 K ∗ ∑ i = 0 N ( a i C − b i c ) K \Rightarrow sq5^K*\sum_{i=0}^N (a^{iC}-b^{ic})^K ⇒sq5K∗∑i=0N(aiC−bic)K
- 二项式展开 ⇒ \Rightarrow ⇒ s q 5 K ∗ ∑ i = 0 N ∑ j = 0 K C k j a i j C ( − b ) ( k − j ) ∗ i C sq5^K*\sum_{i=0}^N \sum_{j=0}^K C_{k}^{j}a^{ijC}(-b)^{(k-j)*iC} sq5K∗∑i=0N∑j=0KCkjaijC(−b)(k−j)∗iC
设 A = a C , B = b C A=a^C,B=b^C A=aC,B=bC
- 代入 ⇒ s q 5 K ∗ ∑ i = 0 N ∑ j = 0 K C k j A i j ( − B i ) k − j \Rightarrow sq5^K*\sum_{i=0}^N \sum_{j=0}^K C_{k}^{j}A^{ij}(-B^i)^{k-j} ⇒sq5K∗∑i=0N∑j=0KCkjAij(−Bi)k−j
- 交换 ⇒ s q 5 K ∗ ∑ j = 0 K C k j ( − 1 ) k − j ∑ i = 0 N ( A j ) i ( B k − j ) i \Rightarrow sq5^K* \sum_{j=0}^KC_{k}^{j}(-1)^{k-j}\sum_{i=0}^N (A^j)^i(B^{k-j})^i ⇒sq5K∗∑j=0KCkj(−1)k−j∑i=0N(Aj)i(Bk−j)i
- ∑ i = 0 N ( A j ) i ( B k − j ) i ⇒ ∑ i = 0 N ( A j ∗ B k − j ) i \sum_{i=0}^N (A^j)^i(B^{k-j})^i\Rightarrow\sum_{i=0}^N (A^j*B^{k-j})^i ∑i=0N(Aj)i(Bk−j)i⇒∑i=0N(Aj∗Bk−j)i
有等比求和公式, ∑ i = 0 N x i = x N + 1 − 1 x − 1 \sum_{i=0}^N x^i=\frac{x^{N+1}-1}{x-1} ∑i=0Nxi=x−1xN+1−1
- ∑ i = 0 N ( A j ∗ B k − j ) i ⇒ ( A j B k − j ) N + 1 − 1 A j B k − j − 1 \sum_{i=0}^N (A^j*B^{k-j})^i\Rightarrow \frac{(A^jB^{k-j})^{N+1}-1}{A^jB^{k-j}-1} ∑i=0N(Aj∗Bk−j)i⇒AjBk−j−1(AjBk−j)N+1−1
所以问题就转化成了:
s
q
5
K
∗
∑
j
=
0
K
C
k
j
(
−
1
)
k
−
j
(
A
j
B
k
−
j
)
N
+
1
−
1
A
j
B
k
−
j
−
1
sq5^K*\sum_{j=0}^KC_{k}^{j}(-1)^{k-j} \frac{(A^jB^{k-j})^{N+1}-1}{A^jB^{k-j}-1}
sq5K∗∑j=0KCkj(−1)k−jAjBk−j−1(AjBk−j)N+1−1
(
A
=
a
C
,
B
=
b
C
)
(A=a^C,B=b^C)
(A=aC,B=bC)
这个代码就比较好写啦^^
注意点:
直接在for循环里面qpow会t,代码如下:
LL fac[maxn], invfac[maxn];
LL sqt5 = 383008016;//根号5二次剩余
LL inv2, invsq5;
LL a, b;
void initfac(LL n) {
fac[0] = 1;
for (LL i = 1; i <= n; i++) { fac[i] = fac[i - 1] * i%MOD; }
invfac[n] = quick_mod(fac[n], MOD - 2, MOD);
for (LL i = n - 1; i >= 0; i--) { invfac[i] = invfac[i + 1] * (i + 1) % MOD; }
return;
}
LL cm(LL n, LL m) {
if (m<0 || m>n) return 0;
return fac[n] * invfac[n - m] % MOD*invfac[m] % MOD;
//return (fac[n] * qpow(fac[m], MOD - 2) % MOD*qpow(fac[n - m], MOD - 2) % MOD) % MOD;
}
LL solve(LL n, LL c, LL k) {
LL ans = 0;
LL A, B;
LL tt, fenmu, CK;
A = quick_mod(a, c % (MOD - 1), MOD);
B = quick_mod(b, c % (MOD - 1), MOD);
/*cout << "ans1: " << -1 * cm(1, 0)*(quick_mod(B, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(B - 1, MOD - 2, MOD)) % MOD << endl;
cout << "ans2:" << cm(1, 1)*(quick_mod(A, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(A - 1, MOD - 2, MOD)) % MOD << endl;*/
for (LL j = 0; j <= k; j++) {
tt = (quick_mod(A, j, MOD)*quick_mod(B, k - j, MOD)) % MOD;
if (tt == 1) {
tt = cm(k, j)*(n + 1) % MOD;
if ((k - j) % 2)tt *= -1;
ans = (tt + ans + MOD) % MOD;
continue;
}
fenmu = (tt - 1 + MOD) % MOD;
tt = quick_mod(tt, (n + 1) % (MOD - 1), MOD);
tt = (tt - 1 + MOD) % MOD;
CK = tt * quick_mod(fenmu, MOD - 2, MOD) % MOD;
CK = (cm(k, j)*CK) % MOD;
//cout << cm(k, j) << endl;
if ((k - j) % 2)CK *= -1;
//cout << "teat: " << CK << endl;
//cout << "test2: " << CK << endl;
ans = (CK + ans + MOD) % MOD;
}
ans = (quick_mod(invsq5, k, MOD)*ans) % MOD;//sq5^K
return ans;
}
int main() {
int t;
LL n, c, k;
inv2 = quick_mod(2, MOD - 2, MOD);//2的逆元
invsq5 = quick_mod(sqt5, MOD - 2, MOD);//根号5分之一的逆元
a = (1 + sqt5)*inv2%MOD;
b = (1 - sqt5 + MOD) % MOD*inv2%MOD;
//cout << a << " " << b << endl;
sci(t);
/*for (LL i = 1; i <= MOD; i++) {
if (i*i%MOD == 5) { cout << i << endl; break; }
}*/
initfac(1e5+5);//初始化,之后要计算排列组合
while (t--)
{
scanf("%lld%lld%lld", &n, &c, &k);
printf("%lld\n", solve(n, c, k));
}
return 0;
}
优化:
在j的循环内对于
(
A
j
B
k
−
j
)
N
+
1
(A^jB^{k-j})^{N+1}
(AjBk−j)N+1的循环进行优化,不要每次都qpow,因为他们有一个初始值
A
0
B
k
A^0B^k
A0Bk,然后只需要每次进行增量
A
B
−
1
AB^{-1}
AB−1,就可以得到这次的
A
j
B
k
−
j
A^jB^{k-j}
AjBk−j
cndmmdldasfhilskkju气死我了wa死了找不出错哪了不管了谁爱做谁做cnmmmmm
🐂我找到了^^tt=1的时候没有mod,好,不愧是我
LL fac[maxn], finv[maxn];
LL sqt5 = 383008016ll;//根号5二次剩余
LL inv2, invsq5;
LL a, b;
void initfac(LL n) {
fac[0] = 1; for (LL i = 1; i <= n; i++) { fac[i] = fac[i - 1] * i%MOD; }
finv[n] = quick_mod(fac[n], MOD - 2);
for (LL i = n - 1; i >= 0; i--) { finv[i] = finv[i + 1] * (i + 1ll) % MOD; }
return;
}
LL cm(LL n, LL m) {//计算组合数
if (m<0 || m>n) return 0;
return (fac[n] * finv[n - m]) % MOD*finv[m] % MOD;
//return (fac[n] * qpow(fac[m], MOD - 2) % MOD*qpow(fac[n - m], MOD - 2) % MOD) % MOD;
}
LL solve(LL n, LL c, LL k) {
LL ans = 0ll;
LL A, B;
LL tt, chushi;
A = quick_mod(a, c % (MOD - 1ll));
B = quick_mod(b, c % (MOD - 1ll));
LL del = A * quick_mod(B, MOD - 2ll) % MOD;
chushi = quick_mod(B, k );//初始值:B^k
/*cout << "ans1: " << -1 * cm(1, 0)*(quick_mod(B, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(B - 1, MOD - 2, MOD)) % MOD << endl;
cout << "ans2:" << cm(1, 1)*(quick_mod(A, (n + 1) % (MOD - 1), MOD) - 1)*(quick_mod(A - 1, MOD - 2, MOD)) % MOD << endl;*/
for (LL j = 0; j <= k; j++) {
if (chushi == 1) {
tt = (n + 1ll) % MOD;
}
else {
tt = (((quick_mod(chushi, (n + 1ll) % (MOD - 1)) - 1 + MOD) % MOD)*(quick_mod((chushi - 1 + MOD) % MOD, MOD - 2))) % MOD;
}
tt = cm(k, j)*tt%MOD;
if ((k - j) % 2 ) {
ans = (ans - tt + MOD) % MOD;
}
else {
ans = (ans + tt) % MOD;
}
chushi = (chushi * del) % MOD;
}
ans = (quick_mod(invsq5, k)*ans) % MOD;//sq5^K
return ans;
}
int main() {
int T;
LL n, c, k;
inv2 = quick_mod(2ll, MOD - 2ll);//2的逆元
invsq5 = quick_mod(sqt5, MOD - 2ll);//根号5分之一的逆元
//cout << invsq5 << endl;
a = (1ll + sqt5)*inv2%MOD;
b = (1ll - sqt5 + MOD) % MOD*inv2%MOD;
//cout << a << " " << b << endl;
sci(T);
initfac(1ll*1e5);//初始化,之后要计算排列组合
while (T--)
{
scanf("%lld%lld%lld", &n, &c, &k);
printf("%lld\n", solve(n, c, k));
}
return 0;
}