题目连接: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)。
(1le Tle 20, 1le nle 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使得
(Acdot egin{pmatrix}
f_{n-1}\f_{n-2}
\ f_{n-3}
\ f_{n-4}
end{pmatrix}=egin{pmatrix}
f_n\ f_{n-1}
\ f_{n-2}
\ f_{n-3}
end{pmatrix})
那么我们很容易得到
(A=egin{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
");
if (n<=4) {printf ("%lld
",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
",ans.mat[1][1]);
}
return 0;
}