多项递推式—(循环节or矩阵快速幂)

点击进入原题?:D: Starry的神奇魔法

Time Limit: 1 s       Memory Limit: 128 MB     

Problem Description

       啦啦啦,Starry正愉快的做着编程题,代码是多么优美呀!突然,有人问他一道数学题,对于数学渣渣的Starry来说,这是多么的烦恼呀。不过不要紧,他还可以问其他人的,所以他想到了聪明的你们。这个问题是由一个神奇的魔法师提出的,他创造了一种魔法,每次使用魔法可以让今天的魔力值为前一天魔力值的2018倍+前两天魔力值的8倍+前三天魔力值的12倍。当然,一天只能使用一次魔法,除了使用魔法外,每天魔法师还能产生8888的魔力值。第一、二、三天的初始魔力值为888。他想问的是第n天他可以拥有多少魔力值。

Input

第一行输入一个T表示有T个问题(1≤T≤104)。

接下来T行,每行有一个数n(1≤n≤1018),表示第n天。

Output

输出T行,每行输出第n天的魔力值,由于数很大,结果对20180812取模。

Sample Input

3
2
5
8

Sample Output

888
17299052
16854116

题意:第一天888,第二天888,第三天888,之后递推式为:f(n)=(f(n-1)*2018+f(n-2)*8+f(n-3)*12+8888)%mod;

思路:多项递推式有两种写法(我指我所知道的0.0),分别是:“求循环节”和“矩阵快速幂优化递推式”。(大数据暴力肯定不行,所以别和我说暴力0.0)

循环节:(顾名思义f(n)到后面是有规律(循环的)):我们可以先试着去找一下这道题的循环节,打印前(20180813)天的,会发现这道题没有循环节。

所以我们使用第二种方法:

矩阵快速幂优化递推式”:?根据递推式:f(n)=(f(n-1)*2018+f(n-2)*8+f(n-3)*12+8888)%mod;得到以下矩阵:?????

 

化简一下:

 

 

所以我们最后要求的f(n)就可以知道了:              上方?的这个矩阵(n-3)次放的结果为sum.m[4][4]

                                                               Tip:题目已经说了f(1),(2),f(3)为888

                                        当(n<=3) f(n)=888;                         

所以当(n>3)时,f(n)=sum.m[0][0]*f(3)+sum.m[0][1]*f(2)+sum.m[0][2]*f(1)+sum.m[0][3]*1)%mod                                                                           

所以当(n>3)时,f(n)=sum.m[0][0]*888+sum.m[0][1]*888+sum.m[0][2]*888+sum.m[0][3])%mod

所以我们这题就变成了求sum.m[4][4]这个矩阵,这里就要用的就是矩阵快速幂啦?。下面直接上代码:

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #define mod 20180812
 5 using namespace std;
 6 struct mat{
 7     long long m[4][4];//这里开4*4就可以 
 8 };
 9 mat map,sum;//map指的是那个4*4原本的矩阵
10 //sum指的是map的(n-3)次放之后的矩阵 
11 long long N;
12 mat muliply(mat a,mat b)//矩阵乘法 
13 {
14     mat c;
15     memset(c.m,0,sizeof(c.m));
16     for(long long  i=0;i<4;i++)
17     for (long long j=0;j<4;j++)
18     for (long long z=0;z<4;z++)
19     {
20         c.m[i][j]+=a.m[i][z]*b.m[z][j];
21         c.m[i][j]%=mod;
22     }
23     return c;
24 }
25 mat poww(mat a,long long n)//快速幂 
26 {
27     memset(sum.m,0,sizeof(sum.m));
28     for (long long i=0;i<4;i++)//单位矩阵 
29     sum.m[i][i]=1;
30     while(n)//快速幂 
31     {
32         if (n&1)
33                sum=muliply(sum,a);
34        a=muliply(a,a);
35         n>>=1;
36     }
37     return sum;
38 }
39 int main()
40 {
41     long long T;
42     scanf("%lld",&T);
43     while(T--)
44     {
45         scanf("%lld",&N);
46         map.m[0][0]=2018;map.m[0][1]=8;map.m[0][2]=12;map.m[0][3]=8888;
47         map.m[1][0]=1;map.m[1][1]=0;map.m[1][2]=0;map.m[1][3]=0;
48         map.m[2][0]=0;map.m[2][1]=1;map.m[2][2]=0;map.m[2][3]=0;
49         map.m[3][0]=0;map.m[3][1]=0;map.m[3][2]=0;map.m[3][3]=1;
50         if (N<=3)
51         {
52             printf("%lld\n",888);
53         }
54         else
55         {
56          sum=poww(map,N-3);//调用矩阵快速幂得到map的(n-3)次放的矩阵 
57              printf("%lld\n",(sum.m[0][0]*888+sum.m[0][1]*888+sum.m[0][2]*888+sum.m[0][3])%mod);
58              //计算得到f(n) 
59         }
60     }
61     return 0;
62 }

 

二:下面是一道之前写的简单的“循环节”题目和解析的博客链接?https://www.cnblogs.com/bendandedaima/p/9323847.html

 

转载于:https://www.cnblogs.com/bendandedaima/p/9466444.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值