Count(HDU 6470)(矩阵快速幂)

Count

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 370    Accepted Submission(s): 148


 

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=10^4,n<=10^18

 

Output

共T行,每行一个正整数表示所求的答案

 

Sample Input

 

5 3 6 9 12 15

 

Sample Output

 

31 700 7486 64651 527023

 

Source

“字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6470 6469 6468 6467 6466 

做这题之前有个题跟 这题极其类似:

F(n) = F(n-1) + 2F(n-2) + n^4

hdu5950

具体解法在这

https://www.jianshu.com/p/25eba927d9da

以上内容来自  https://www.jianshu.com/p/25eba927d9da

/*

我们把解决这类题目的过程分解为如下步骤:
1. 把非线性递推式转化为线性递推式(线性递推式可忽略第一步)
2. 根据线性递推式得到F(n)和F(n+1)的矩阵序列
3. 根据F(n)和F(n+1)的矩阵序列得到中间的转移矩阵
4. 根据转移矩阵编写代码

分步拆解问题

首先把非线性递推式转换为线性递推式
∵ (n+1)4 = n4 + 4n3 + 6n2 + 4n + n0
∵ F(n+1) = F(n) + 2F(n-1) + (n+1)4
∴ F(n+1) = F(n) + 2F(n-1) + n4 + 4n3 + 6n2 + 4n + n0

然后我们看下下面的状态转移矩阵

图有误,等号左边两个矩阵位置换一下

图(1)左边的矩阵表示F(n)项的矩阵,右边的矩阵表示F(n+1)项的矩阵。而中间的A矩阵就是需要求的转移矩阵。图(1)左边的矩阵怎么得到?我们看刚才得到的递归式

F(n+1) = F(n) + 2F(n-1) + n4 + 4n3 + 6n2 + 4n + n0

我们把F(n)放在矩阵顶部,表示第n项的值,然后剩下的元素F(n-1)、 n4、n3、n2、n、 n0 ,去掉系数后与F(n)一起构成一个矩阵。同理,F(n+1)的矩阵也是F(n+1)在顶部,表示第n+1项的值,然后剩下的元素F(n)、 (n+1)4、(n+1)3、(n+1)2、(n+1)、 (n+1)0 去掉系数后与F(n+1)构成一个矩阵。

好,我们现在得到了F(n)F(n+1)的矩阵,那怎么求转移过去的矩阵A呢?首先,A是一个7×7的矩阵,且根据矩阵相乘规则,可以得到矩阵A,如下图(如果对矩阵相乘不熟悉的可以先看一下矩阵相乘哈)

图有误,等号左边两个矩阵位置换一下

好了,到现在为止,得到了图(2)的转移矩阵后,我们解决了前三步,还剩最后一步。怎么把这个转移矩阵应用到代码里面呢?

题中给出了F(1) = a,F(2) = b
所以F(3) = 2a + b + 34 = 2a + b + 24 + 4×23 + 6×22 + 4×21 + 20

图(3)



作者:徐森威
链接:https://www.jianshu.com/p/25eba927d9da
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

*/

这里是F[n]=F[n-1]+2F[n-2]+n^3;

看完解法是不是感觉很妙,好我们就依葫芦画瓢,写这个题。将(n+1)^3拆分就是n^3+3*n^2+3*n+n^0;

上图,

\begin{pmatrix} \\ f[n+1] \\f[n] \\(n+1)^{3} \\(n+1)^{2} \\(n+1)^{1} \\(n+1)^{0} \end{pmatrix}===[A]*      \begin{pmatrix} \\ f[n] \\ f[n-1] \\ (n)^{3} \\ (n)^{2} \\ (n)^{1} \\(n)^{0} \end{pmatrix},然后通过简单的构造可以得出目的矩阵A=\begin{bmatrix} 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 \end{bmatrix}

再套用矩阵快速幂的模板即可~~~~~~~~~~~~~~~AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=6;
const ll mod=123456789;

struct Matrix
{
	ll mat[MAXN][MAXN];
	Matrix() {}
	Matrix operator*(Matrix const &b)const
	{
		Matrix res;
		memset(res.mat, 0, sizeof(res.mat));
		for (int i = 0 ;i < MAXN; i++)
			for (int j = 0; j < MAXN; j++)
				for (int k = 0; k < MAXN; k++)
					res.mat[i][j] = (res.mat[i][j]+this->mat[i][k] * b.mat[k][j])%mod;
		return res;
	}
};
Matrix pow_mod(Matrix base, ll n)
{
	Matrix res;
	memset(res.mat, 0, sizeof(res.mat));
	for (int i = 0; i < MAXN; i++)
		res.mat[i][i] = 1;
	while (n > 0)
	{
		if (n & 1) res = res*base;
		base = base*base;
		n >>= 1;
	}
	return res;
}
Matrix base,fi;
void init()
{
    base.mat[0][0]=1;
    base.mat[0][1]=2;
    base.mat[0][2]=1;
    base.mat[0][3]=3;
    base.mat[0][4]=3;
    base.mat[0][5]=1;

    base.mat[1][0]=1;

    base.mat[2][2]=1;
    base.mat[2][3]=3;
    base.mat[2][4]=3;
    base.mat[2][5]=1;

    base.mat[3][3]=1;
    base.mat[3][4]=2;
    base.mat[3][5]=1;

    base.mat[4][4]=1;
    base.mat[4][5]=1;

    base.mat[5][5]=1;

    fi.mat[0][0]=2;
	fi.mat[1][0]=1;
	fi.mat[2][0]=8;
	fi.mat[3][0]=4;
	fi.mat[4][0]=2;
	fi.mat[5][0]=1;
}
int main()
{
	init();
	int t;
	ll n;
	cin>>t;
	while (t--)
	{
        scanf("%lld", &n);
	    if(n<=2)
        {
            printf("%d\n",n);
            continue;
        }
		Matrix ans = pow_mod(base, n-2);
		ans=ans*fi;
		printf("%lld\n", ans.mat[0][0]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/88632673
今日推荐