Starry的神奇魔法 矩阵快速幂
题目描述
啦啦啦,Starry正愉快的做着编程题,代码是多么优美呀!突然,有人问他一道数学题,对于数学渣渣的Starry来说,这是多么的烦恼呀。不过不要紧,他还可以问其他人的,所以他想到了聪明的你们。这个问题是由一个神奇的魔法师提出的,他创造了一种魔法,每次使用魔法可以让今天的魔力值为前一天魔力值的2018倍+前两天魔力值的8倍+前三天魔力值的12倍。当然,一天只能使用一次魔法,除了使用魔法外,每天魔法师还能产生8888的魔力值。第一、二、三天的初始魔力值为888。他想问的是第n天他可以拥有多少魔力值。
输入
第一行输入一个T表示有TT个问题(1≤T≤104)(1≤T≤104)。
接下来T行,每行有一个数n(1≤n≤1018)n(1≤n≤1018),表示第nn天。
输出
输出TT行,每行输出第nn天的魔力值,由于数很大,结果对2018081220180812取模。
样例输入
3
2
5
8
样例输出
888 17299052 16854116
解题思路:数据太大,不能打表不能暴力,就用矩阵快速幂。
矩阵1:{888,888,888,8888},矩阵二:{{2018,1,0,0},{8,0,1,0},{12,0,0,0},{1,0,0,1}};
矩阵1的意义:{f1,f2,f3,c},fn为第几的天数,c为常量。推导见基础矩阵快速幂的斐波那契数列;参考博客:https://www.cnblogs.com/cmmdc/p/6936196.html
以下为ac代码:
1 #include<iostream> 2 using namespace std; 3 const int mod=20180812; 4 struct P{ 5 long long a[4][4]; 6 }num,rex; 7 long long f[4]; 8 void init() 9 { 10 f[0]=f[1]=f[2]=888;f[3]=8888; 11 num.a[0][0]=2018;num.a[0][1]=1;num.a[0][2]=0;num.a[0][3]=0; 12 num.a[1][0]=8;num.a[1][1]=0;num.a[1][2]=1;num.a[1][3]=0; 13 num.a[2][0]=12;num.a[2][1]=0;num.a[2][2]=0;num.a[2][3]=0; 14 num.a[3][0]=1;num.a[3][1]=0;num.a[3][2]=0;num.a[3][3]=1; 15 return; 16 } 17 P fun(P x,P y) 18 { 19 P tmp; 20 for(int i=0;i<4;i++) 21 for(int j=0;j<4;j++) 22 tmp.a[i][j]=0; 23 for(int i=0;i<4;i++) 24 for(int j=0;j<4;j++) 25 for(int k=0;k<4;k++) 26 tmp.a[i][j]=(tmp.a[i][j]+(x.a[i][k]*y.a[k][j])%mod)%mod; 27 return tmp; 28 } 29 void quickp(long long n) 30 { 31 for(int i=0;i<4;i++) 32 for(int j=0;j<4;j++) 33 { 34 if(i==j) rex.a[i][j]=1; 35 else rex.a[i][j]=0; 36 } 37 while(n) 38 { 39 if(n&1) 40 rex=fun(rex,num); 41 num=fun(num,num); 42 n>>=1; 43 } 44 return; 45 } 46 int main() 47 { 48 long long t,n; 49 scanf("%lld",&t); 50 while(t--) 51 { 52 long long ans=0; 53 init(); 54 scanf("%lld",&n); 55 if(n<=3) 56 cout<<"888"<<endl; 57 else 58 { 59 quickp(n-3); 60 for(int i=0;i<4;i++) 61 ans=(ans+(f[i]*rex.a[i][0])%mod)%mod; 62 printf("%lld\n",ans); 63 } 64 } 65 return 0; 66 }