程序设计思维与实践 Week14 作业 C Q老师的考验

题目描述:

Q老师 对数列有一种非同一般的热爱,尤其是优美的斐波那契数列。

这一天,Q老师 为了增强大家对于斐波那契数列的理解,决定在斐波那契的基础上创建一个新的数列 f(x) 来考一考大家。数列 f(x) 定义如下:

当 x < 10 时,f(x) = x;
当 x ≥ 10 时,f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10),ai 只能为 0 或 1。

Q老师 将给定 a0~a9,以及两个正整数 k m,询问 f(k) % m 的数值大小。

聪明的你能通过 Q老师 的考验吗?

input:

输出文件包含多组测试用例,每组测试用例格式如下:

第一行给定两个正整数 k m。(k < 2e9, m < 1e5)

第二行给定十个整数,分别表示 a0~a9。

output:

对于每一组测试用例输出一行,表示 f(k) % m 的数值大小。

思路:

根据递推公式,构造快速幂矩阵,通过计算,最终的答案向量将是快速幂矩阵的k-9次方乘初始向量a9 a8 ...a0

快速幂矩阵及其乘法运算通过结构体的方式进行了封装并重载*运算符。

最终结果如下:

时间复杂度:log(k)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int k,m,a[11];
struct node
{
	long long n[11][11];
	node operator *(const node &t)
	{
		node ans;
		for(int i=1;i<=10;i++)
		  for(int j=1;j<=10;j++)
		    for(int k=1;k<=10;k++)
		    ans.n[i][j]=(ans.n[i][j]+((n[i][k]%m)*(t.n[k][j]%m))%m)%m;
		return ans;
	}
	node(){memset(n,0,sizeof(n));}
	node(int*t)
	{
		memset(n,0,sizeof(n));
		for(int i=1;i<=10;i++)
		n[1][i]=t[i];
		for(int i=2;i<=10;i++)
		n[i][i-1]=1;
	}
};
int main()
{
	while(scanf("%d%d",&k,&m)!=EOF)
	{
		for(int i=1;i<=10;i++)
		cin>>a[i];
		node t(a);
		node ans;
		for(int i=1;i<=10;i++)
		ans.n[i][i]=1;
		if(k<10)
		{
			cout<<k<<endl;
			continue;
		}
		k-=9;
		while(k)
		{
			if(k&1) ans=ans*t;
			t=t*t;
			k>>=1;
		}
		long long fina=0;
		for(int i=1;i<=10;i++)
		fina=(fina+ans.n[1][i]*(10-i))%m;
		cout<<fina<<endl;
	}
	return 0;
}

 

Guess you like

Origin blog.csdn.net/cax1165/article/details/106276087