Problem Description
Farmer John有n头奶牛.
某天奶牛想要数一数有多少头奶牛,以一种特殊的方式:
第一头奶牛为1号,第二头奶牛为2号,第三头奶牛之后,假如当前奶牛是第n头,那么他的编号就是2倍的第n-2头奶牛的编号加上第n-1头奶牛的编号再加上自己当前的n的三次方为自己的编号.
现在Farmer John想知道,第n头奶牛的编号是多少,估计答案会很大,你只要输出答案对于123456789取模.
Input
第一行输入一个T,表示有T组样例
接下来T行,每行有一个正整数n,表示有n头奶牛 (n>=3)
其中,T=104,n<=1018
Output
共T行,每行一个正整数表示所求的答案
Sample Input
5
3
6
9
12
15
Sample Output
31
700
7486
64651
527023
Source
“字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛
分析:看到递推式+取模+大数n,很显然,一个纯模板的矩阵快速幂,构造出转移矩阵再套上模板就可以了。
A B C
1 2 1 3 3 1 f2=2 f3
1 0 0 0 0 0 f1=1 f2
0 0 1 3 3 1 * i*i*i=8 = (i+1)*(i+1)*(i+1)=27
0 0 0 1 2 1 i*i=4 (i+1)*(i+1)=9
0 0 0 0 1 1 i=2 i+1=3
0 0 0 0 0 0 1 1
//求第N项就是先求A的n-2次方再乘B,就得出ans.
菜鸡(me)不会封装矩阵,凑合着看哈
#include <iostream>
#include <cstdio>
#include <string>
#include<cstring>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 6;
ll mod=123456789;
int main()
{
ll t;
scanf("%lld",&t);//一个cin,cout也不要用,会T
while (t--){
ll n;scanf("%lld",&n);
n-=2;
ll a[6][6]={{1,2,1,3,3,1},{1,0,0,0,0,0},{0,0,1,3,3,1},{0,0,0,1,2,1},{0,0,0,0,1,1},{0,0,0,0,0,1}};
ll s[6][6]={0};
for(int i=0;i<maxn;i++)s[i][i]=1;
while (n){
if(n&1){
ll d[maxn][maxn]={0};
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
for(int k=0;k<maxn;k++)
d[i][j]+=a[i][k]*s[k][j]%mod;
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
s[i][j]=d[i][j];
}
ll d[maxn][maxn]={0};
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
for(int k=0;k<maxn;k++)
d[i][j]+=a[i][k]*a[k][j]%mod;
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
a[i][j]=d[i][j];
n>>=1;
}
ll ans=(s[0][0]*2%mod+s[0][1]*1%mod+s[0][2]*8%mod+s[0][3]*4%mod+s[0][4]*2%mod+s[0][5]*1%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}