显然是一道矩阵加速的题。
发现不好做,不妨推一下式子。
a i = f ( i ) ∗ i k a_i=f(i)*i^k ai=f(i)∗ik
< = > a i = ( f i − 1 + f i − 2 ) ∗ i k <=> a_i=(f_{i-1}+f_{i-2})*i^k <=>ai=(fi−1+fi−2)∗ik
< = > a i = ( f i − 1 ∗ ( i − 1 + 1 ) k + f i − 2 ∗ ( i − 2 + 2 ) k ) <=> a_i=(f_{i-1}*(i-1+1)^k+f_{i-2}*(i-2+2)^k) <=>ai=(fi−1∗(i−1+1)k+fi−2∗(i−2+2)k)
< = > a i = f i − 1 × ∑ C ( u , k ) × ( i − 1 ) u + f i − 2 × ∑ C ( v , k ) × ( i − 2 ) v × 2 k − v ( 0 ≤ u , v ≤ k ) <=> a_i=f_{i-1}\times \sum{C(u,k)\times (i-1)^u}+f_{i-2}\times\sum{C(v,k)\times (i-2)^v \times 2^{k-v}}(0\leq u,v \leq k) <=>ai=fi−1×∑C(u,k)×(i−1)u+fi−2×∑C(v,k)×(i−2)v×2k−v(0≤u,v≤k)
< = > a i = ∑ C ( u , k ) × f i − 1 × ( i − 1 ) u + ∑ C ( v , k ) × f i − 2 × ( i − 2 ) v × 2 k − v ( 0 ≤ u , v ≤ k ) <=> a_i=\sum{C(u,k)\times f_{i-1}\times (i-1)^u}+\sum{C(v,k)\times f_{i-2}\times(i-2)^v \times 2^{k-v}}(0\leq u,v \leq k) <=>ai=∑C(u,k)×fi−1×(i−1)u+∑C(v,k)×fi−2×(i−2)v×2k−v(0≤u,v≤k)
关于 f i − 1 ( i − 1 ) u / f i − 2 ( i − 2 ) v f_{i-1}(i-1)^u/f_{i-2}(i-2)^v fi−1(i−1)u/fi−2(i−2)v,用二项式定理进行矩阵加速即可。
所以目标矩阵大概是这个样子:
[ f i , f i − 1 , a n s i , f i i 0 , f i i 1 , . . , f i i k , f i − 1 ( i − 1 ) 0 , f i − 1 ( i − 1 ) 1 , . . . , f i − 1 ( i − 1 ) k ] [f_i, f_{i-1}, ans_i, f_ii^0,f_ii^1, .., f_ii^k, f_{i-1}(i-1)^0, f_{i-1}(i-1)^1, ..., f_{i-1}(i-1)^k] [fi,fi−1,ansi,fii0,fii1,..,fiik,fi−1(i−1)0,fi−1(i−1)1,...,fi−1(i−1)k]
(具体的转移矩阵请读者自己去推,我懒得打上去了,大概长下面这个样子。。。)
时间复杂度: O ( k 3 l o g 2 ( n ) ) \mathcal{O}(k^3log_2(n)) O(k3log2(n))。
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 100, Mod = 1e9 + 7;
LL n;
int k, C[MAXN][MAXN], cnt, Pow[MAXN], a[MAXN], res;
struct Fuck {
int s[MAXN][MAXN];
Fuck() {}
Fuck(int S[][MAXN]) {
for(int i = 1; i <= cnt; i ++) for(int j = 1; j <= cnt; j ++) s[i][j] = S[i][j];
}
Fuck operator * (const Fuck P) const {
Fuck ans;
for(int i = 1; i <= cnt; i ++) for(int j = 1; j <= cnt; j ++) ans.s[i][j] = 0;
for(int i = 1; i <= cnt; i ++) for(int j = 1; j <= cnt; j ++) for(int u = 1; u <= cnt; u ++) ans.s[i][j] = (ans.s[i][j] + (LL)s[i][u] * P.s[u][j] % Mod) % Mod;
return ans;
}
};
Fuck Quick_Pow(Fuck x, LL T) {
Fuck ans = x;
for(; T; T >>= 1) {
if(T & 1) ans = ans * x;
x = x * x;
}
return ans;
}
int main() {
Fuck t;
scanf("%lld%d", &n, &k); Pow[0] = 1; cnt = (k << 1) + 5;
for(int i = 0; i <= k; i ++) C[0][i] = 1, C[i][i] = 1;
for(int i = 1; i <= k; i ++) for(int j = i + 1; j <= k; j ++) C[i][j] = (C[i][j - 1] + C[i - 1][j - 1]) % Mod;
for(int i = 1; i <= k + 1; i ++) Pow[i] = Pow[i - 1] * 2 % Mod;
if(n == 1) { printf("1"); return 0; }
if(n == 2) { printf("%d", (Pow[k + 1] + 1) % Mod); return 0; }
t.s[1][1] = t.s[2][1] = t.s[1][2] = t.s[3][3] = 1;
for(int i = 4; i <= 4 + k; i ++) t.s[i][3] = C[i - 4][k];
for(int i = 5 + k; i <= 5 + 2 * k; i ++) t.s[i][3] = (LL)C[i - 5 - k][k] * Pow[5 + 2 * k - i] % Mod;
for(int i = 4; i <= 4 + k; i ++) {
for(int j = 4; j <= i; j ++) t.s[j][i] = C[j - 4][i - 4];
for(int j = k + 5; j <= k + i + 1; j ++) t.s[j][i] = (LL)C[j - k - 5][i - 4] * Pow[k + i + 1 - j] % Mod;
}
for(int i = 5 + k; i <= 5 + 2 * k; i ++) t.s[i - k - 1][i] = 1;
t = Quick_Pow(t, n - 3); a[1] = 2; a[2] = 1; a[3] = ((1LL << (k + 1)) + 1) % Mod;
for(int i = 4; i <= k + 4; i ++) a[i] = Pow[i - 3];
for(int i = k + 5; i <= 2 * k + 5; i ++) a[i] = 1;
for(int i = 1; i <= 2 * k + 5; i ++) res = (res + (LL)a[i] * t.s[i][3] % Mod) % Mod;
printf("%d", res);
return 0;
}