题意:
给定一个\(k\)维的\(n^k\)的超立方体,超立方体的元素\(A(i1,i2,...,ik)\)的值为\(f(i1+i2+...+ik-k+1)\),f为斐波那契数列
求该超立方体的所有元素和
\(1 \le n,k \le 10^9\)
输入样例
3
2 2
4 1
1 3
输出样例
5
7
1
题解
自己好长时间没写题解了,自己好懒啊。
假如k=1,那么就是答案就是斐波那契数列的前缀和。
这里有一个神奇的结论 :设\(f[i]\)为斐波那契数列的第\(i\)项,则\(\displaystyle \sum_{i=1}^{n}f[i]=f[n+2]-f[2]\)
我们用矩阵快速幂就能解决啦。
假如k<=100,我们就需要用到一个神奇的结论了:当我们做完一维后,可以把这维看成成一个点,权值是这维的和。
我们先来考虑只有两维的情况,我们求的就是\(\displaystyle \sum_{i=1}^{n}(\sum_{j=1}^{n}f[i+j])\),我们发现我们求完了一维后,将这一维压缩成前缀和后,我们会面临相同的子问题。推广到k维依然适合,所以我们可以用k次快速幂来解决。
假如k更大,我们可以考虑维之间的转化,假如我们求出了转移到下一维的矩阵B,我们用初始矩阵\(A\)乘上\(B^k\)就能求出来答案。
那B怎么求呢?我们发现维度的转换只用求出来这一维的前缀和就行了,而刚刚的\(\displaystyle \sum_{i=1}^{n}f[i]=f[n+2]-f[2]\)在更高维上显然依然适用,将公式套到矩阵上就可以啦。
#include<iostream> #include<cstring> #include<cstdio> #define LL long long using namespace std; const int mod=1e9+7; LL n,k,T; struct ju { LL v[3][3]; friend ju operator *(const ju &a,const ju &b) { ju c;memset(c.v,0,sizeof(c.v)); for(int i=1;i<=2;++i) for(int j=1;j<=2;++j) for(int k=1;k<=2;++k) (c.v[i][j]+=a.v[i][k]*b.v[k][j])%=mod; return c; } friend ju operator -(const ju &a,const ju &b) { ju c;memset(c.v,0,sizeof(c.v)); for(int i=1;i<=2;++i) for(int j=1;j<=2;++j) c.v[i][j]=(a.v[i][j]-b.v[i][j]+mod)%mod; return c; } }A,B; void YYCH() { A.v[1][1]=1;A.v[1][2]=0; B.v[1][1]=1;B.v[1][2]=1;B.v[2][1]=1; } ju ksm(ju a,LL b) { ju res;memset(res.v,0,sizeof(res.v)); res.v[1][1]=res.v[2][2]=1; for(;b;b>>=1,a=a*a) if(b&1)res=res*a; return res; } int main() { YYCH(); cin>>T; while(T--) { scanf("%lld%lld",&n,&k); printf("%lld\n",(A*ksm(ksm(B,n+1)-B,k)).v[1][1]); } return 0; }
来源:https://www.cnblogs.com/wljss/p/12300967.html