【全国互虐】Fibonacci矩阵

orz啊又被屠了 人生如此艰难

 

题意:

给定一个k维的n^k的超立方体 超立方体的元素Ai1,i2,...,ik 的值为f(i1+i2+...+ik-k+1) f为斐波那契数列

求该超立方体的所有元素和

1<=n,k<=10^9

 

题解:

其实看到数据范围 就大概猜到是矩阵乘法了

但是我考试的时候想了半天还是不知道矩阵乘法怎么搞 - -

其实矩阵乘法比我想象中的厉害多了

 

这里有个性质 做完一维后 可以把这维压缩成一个点 用这维的和代替

并且压缩后下一维还是满足斐波那契的性质所以可以用同一个矩阵继续乘
那么把开始的[f[1],f[2],sum[1]] 改为[sum[n],sum[n]-f[1]+f[n+1],sum[n]] 继续快速幂即可

但是这样做的时间复杂度是O(klogn)的

 

其实上面的将[f[1],f[2],sum[1]] 改为[sum[n],sum[n]-f[1]+f[n+1],sum[n]]也是能用矩阵表示出来的orz

具体自己yy下 这样就能求出从这维转到下一维的矩阵是什么样的 这个矩阵的k次方就能求出答案

时间复杂度O(log(nk))

 

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 typedef long long ll;
 4 struct info{
 5     ll n,m;
 6     ll a[3][3];
 7 }save,jz,one,st;
 8 const ll mo=1000000007;
 9 ll t,n,m;
10 inline info operator*(info a,info b){
11     info res;
12     res.n=a.n,res.m=b.m;
13     for (ll i=0;i<res.n;i++)
14     for (ll j=0;j<res.m;j++){
15         res.a[i][j]=0;
16         for (ll k=0;k<a.m;k++) res.a[i][j]=(res.a[i][j]+a.a[i][k]*b.a[k][j]%mo)%mo;
17     }
18     return res;
19 }
20 void makeinfo(){
21     memset(st.a,0,sizeof(st.a));
22     memset(one.a,0,sizeof(one.a));
23     memset(save.a,0,sizeof(save.a));
24     st.n=1,st.m=3;
25     st.a[0][0]=1,st.a[0][1]=1,st.a[0][2]=1;
26     one.n=one.m=save.n=save.m=3;
27     one.a[0][0]=one.a[1][1]=one.a[2][2]=1;
28     save.a[0][1]=save.a[1][2]=save.a[1][0]=save.a[1][1]=save.a[2][2]=1;
29 }
30 info mi(info a,ll b){
31     info res=one;
32     for (;b;b>>=1){
33         if (b&1) res=res*a;
34         a=a*a;
35     }
36     return res;
37 }
38 int main(){
39     freopen("fibonacci.in","r",stdin);
40     freopen("fibonacci.out","w",stdout);
41     scanf("%I64d",&t);
42     makeinfo();
43     for (;t;t--){
44         scanf("%I64d%I64d",&n,&m);
45         jz=mi(save,n-1);
46         jz.a[0][1]=jz.a[0][1]+jz.a[0][2]-1;
47         jz.a[1][1]=jz.a[1][1]+jz.a[1][2];
48         jz.a[2][1]=jz.a[2][1]+jz.a[2][2];
49         jz.a[0][0]=jz.a[0][2];
50         jz.a[1][0]=jz.a[1][2];
51         jz.a[2][0]=jz.a[2][2];
52         jz=mi(jz,m);
53         jz=st*jz;
54         printf("%I64d\n",jz.a[0][0]);
55     }
56     fclose(stdin);
57     fclose(stdout);
58 }
View Code

 

转载于:https://www.cnblogs.com/g-word/p/3757347.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值