CSUSTOJ-藤原书记想要探病(简单矩阵快速幂)

题目连接:http://acm.csust.edu.cn/problem/4044
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/109456571

Description

呜呜呜,辉夜大小姐生病了,学生会的三人正在决定由谁去探病,藤原书记知道辉夜大小姐生病后会变的非常可爱,所以她非常想要获得这次探病的机会,于是她提出了一个数学游戏,显然,向白银和石上挑战数学游戏是非常的愚蠢的,但是这次不一样,他找到了秀知院数学第一的你来帮她作弊,这次的游戏的内容和斐波那契数列有关。

斐波那契数列指的是这样一个数列:\(0、1、1、2、3、5、8、13、21、34、……\) 在数学上,斐波那契数列以如下被以递推的方法定义:\(F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)\)

这次游戏分为两个问题:

首先给定一个 \(n\)

问题一:你要在斐波那契数列中选择任意个不重复的数,使这几个数的和等于 \(n\) ,如果存在合法的方案,请输出 \(Darling\) , 否则输出 \(o~ha~you\)

问题二:你可以在 \(1, 2, 4\) 这三个数中每个数选择任意多个,使这些数的和为 \(n\) ,请计算出有多少种选择的方案数,这个方案数可能很大,请把结果对 \(998244353\) 取模后输出。注意,数字先后选择顺序不同也代表不同方案数,请看样例解释。

这对藤原书记来说太难了,所以请你尽快计算出答案,使她可以去探病。

input

输入第一行一个整数\(T\)表示数据组数。

接下来\(T\)行每行一个整数表示\(n\)

\(1\le T\le 20, 1\le n\le 10000000000\)

output

每组数据都输出\(2\)行,表示两个问题的答案。

Sample Input 1
2
2
4
Sample Output 1
Darling
2
Darling
6

Hint

对于第一组数据:

第一个问题,PPH直接跳一步且步长为\(2\)米即可。

第二个问题,PPH有两种方案:\(\{1,1\},\{2\}\)

对于第二组数据:

第一个问题,PPH先跳一步且步长为\(1\)米,再跳一步步长为\(3\)米即可。

第二个问题,PPH有六种方案:\(\{1,1,1,1\},\{1,1,2\},\{1,2,1\},\{2,2\},\{2,1,1\},\{4\}\)

emmm,刚开始的时候看到这题还感觉出的太简单了,这不是送分嘛。。。后来瞄了一眼数据范围,emmm,挺好的,加了个算法,虽然挺裸的,但没学过还真不知道怎么搞。

首先暴力的写法很简单,就是一个递推式子:\(dp[i]=dp[i-1]+dp[i-2]+dp[i-4]\),对于第一问其实我们可以直接得出Darling,因为所有的整数都可以用斐波那契数列来表示的,所以并不会有什么no的方案。

这题关键的地方在于求解方案数,也就是第二问。我们知道快速求一个递推式可以使用矩阵来加速它,那么直接上手就完事了。由于递推式中有到i-4这里,所以我们需要用到4维矩阵,那么也就是构建一个方阵A使得
\(A\cdot \begin{pmatrix} f_{n-1}\\f_{n-2} \\ f_{n-3} \\ f_{n-4} \end{pmatrix}=\begin{pmatrix} f_n\\ f_{n-1} \\ f_{n-2} \\ f_{n-3} \end{pmatrix}\)
那么我们很容易得到
\(A=\begin{pmatrix} 1 & 1 & 0 & 1\\ 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0 \end{pmatrix}\)

于是矩阵快速幂写一写,实际上也就是个普通的快速幂加上一个矩阵乘法而已。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod=998244353;

struct Mat
{
	ll mat[5][5];
	Mat(){memset(mat,0,sizeof mat);}
};
ll dp[6];

Mat mult(Mat a,Mat b)
{
	Mat ans;
	for (int i=1; i<=4; i++)
		for (int j=1; j<=4; j++)
			for (int k=1; k<=4; k++)
				ans.mat[i][j]=(ans.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;
	return ans;
}

Mat qick(Mat a,ll b)
{
	Mat ans;
	ans.mat[1][1]=ans.mat[2][2]=ans.mat[3][3]=ans.mat[4][4]=1;
	while (b){
		if (b&1) ans=mult(ans,a);
		b>>=1;
		a=mult(a,a);
	}
	return ans;
}

int main(int argc, char const *argv[])
{
	int t;
	dp[1]=1; dp[2]=2; dp[3]=3; dp[4]=6;
	scanf ("%d",&t);
	while (t--){
		ll n;
		scanf ("%lld",&n);
		printf ("Darling\n");
		if (n<=4) {printf ("%lld\n",dp[n]); continue;}
		Mat a;
		a.mat[1][1]=a.mat[1][2]=a.mat[1][4]=1;
		a.mat[2][1]=a.mat[3][2]=a.mat[4][3]=1;
		Mat ans=qick(a,n-4);
		Mat base;
		base.mat[1][1]=dp[4]; base.mat[2][1]=dp[3]; 
		base.mat[3][1]=dp[2]; base.mat[4][1]=dp[1];
		ans=mult(ans,base);
		printf("%lld\n",ans.mat[1][1]);
	}
	return 0;
}
posted @ 2020-11-07 18:35  lonely_wind  阅读(160)  评论(0编辑  收藏  举报