你最愿意做的哪件事,才是你的天赋所在

0%

十七届同济大学程序设计预选赛-J

题目链接

十七届同济大学程序设计预选赛-J

思路

我们从这个开始考虑

上面两个式子做差得到

得到递推式子

使用矩阵来得到所有的$F’_k(n)$,首先矩阵内需要有$Fib[i],Fib[i-1],F’_0[i],\dots,F’_k[i]$,$F’_0[i]=F’_[i-1]+Fib[i-2]+Fib[i-1]$,其他的用上面的式子推出,这样就得到一个k+3的矩阵。
得到上述的所有0~k的$F’_j[n]$之后,我们来还原,

这样就能求出$F_k(n)$了。

代码示例

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 998244353;
struct Mat{
ll a[105][105];
Mat(){
memset(a,0,sizeof(a));
}
ll* operator[](int i){
return a[i];
}
};
int N = 104;
Mat operator * (Mat &a,Mat &b){
Mat res;
for(int i=0;i<N;i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
res[i][j] += a[i][k] * b[k][j] % mod;
}
res[i][j] %= mod;
}
}
return res;
}
ll C[505][505];
ll f_b[505],f[505],pown[505];
Mat quick_pow(Mat a,ll p){
Mat res;
for(int i=0;i<N;i++)res[i][i]=1;
while(p){
if(p&1)res=a*res;
a=a*a;
p>>=1;
}
return res;
}
void init(){
C[0][0]=1;
for(int i=0;i<=500;i++){
for(int j=0;j<=i;j++){
C[i+1][j]+=C[i][j];
C[i+1][j+1]+=C[i][j];
C[i][j]%=mod;
C[i+1][j+1]%=mod;
}
}
}
int main(){
ll n,k;
cin>>n>>k;
init();
pown[0]=1;
for(int i=1;i<=k;i++){
pown[i]=pown[i-1]*(n%mod)%mod;
}
N = k + 3;
Mat a;
a[0][0]=1;
a[0][1]=1;
a[1][0]=1;
a[2][2]=1;
a[2][0]=1;
a[2][1]=1;//对应前三项斐波那契以及F'[0]
for(int i=1;i<=k;i++){
for(int j=0;j<=i;j++){
a[i+2][j+2]=C[i][j];//对应后面的0~k
}
}
a=quick_pow(a,n);
for(int i=0;i<=k;i++){
f_b[i]=a[i+2][1];
}
f[0]=f_b[0];
for(int i=1;i<=k;i++)//转换
{
ll fi = f_b[i];
ll flag = 1;
for(int j=0;j<i;j++){
flag = mod - flag;
fi+=flag*C[i][j]%mod*pown[i-j]%mod*f[j]%mod;
}
fi%=mod;
fi*=flag;
f[i]=fi%mod;
}
cout<<f[k]<<endl;
}
-------------你最愿意做的哪件事才是你的天赋所在-------------