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

题目连接:http://acm.csust.edu.cn/problem/4044
博客园食用链接: https://www.cnblogs.com/lonely-wind-/p/13941879.html

Description

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

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

这次游戏分为两个问题:

首先给定一个 n n n

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

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

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

input

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

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

1 ≤ T ≤ 20 , 1 ≤ n ≤ 10000000000 1\le T\le 20, 1\le n\le 10000000000 1T20,1n10000000000

output

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

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

Hint

对于第一组数据:

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

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

对于第二组数据:

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

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

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

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

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

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

以下是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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值