【矩阵乘法】 【SSL 1532】 递推

【矩阵乘法】 【SSL 1532】 递推

题目

动态规划的实现形式之一是递推,因此递推在oi中十分重要。在某信息学的分支学科中,LC学会了如何求一阶线性递推数列。由于他现在正在学习主干学科,因此希望知道求出N阶线性递推数列。为此,他了解到以下内容:
一个N阶线性递推式是这样的式子:
  F1=a0Fi-n+a1Fi-(n-1)+…+an-1*Fi-1+an
  也就是说,这个数列的每一项都是由他之前的连续N项加权相加所得。其中还包括一个常数an。
  例如,当N=2,a0=a1=1,a2=0时,这个式子就是我们熟悉的斐波那契数列。当然,作为边界条件。f0,f1,…fn-1都是已知的。
  Lc对如何去求这个式子一筹莫展,因此他想请你帮忙。你的任务是对于一个给定的N阶线性递推式,求出他的第k项。


输入

第一行两个整数:n,k。其中n表示这是一个N阶线性递推式,k表示你需要球的那一项。
第二行有n+1个整数:a0,a1,…an,表示这个递推式的系数。
第三行有n个整数:f0,f1,…,fn-1表示数列的初始值。


输出

只有一行,其中只有一个整数,表示这个数列第k项的值。由于数据较大,你只需输出mod 9973的值。


样例

input
2 10
1 1 0
0 1

output
55


数据范围

对于50%的数据 n<=k<=10^6
对于100%的数据
1n<=k<=10^18
1<=ai,fi<=10^4


解题思路

题意
给出前n项和其系数以及一项常数
f[n]=a0 * f[i-n] + a1 * f[i-n+1] + … + an
求这个数列的第k项

思路
题目举例了斐波拉契数列的求法
答案矩阵应该是f[i-2],f[i-1],1
相乘矩阵如下
在这里插入图片描述
因为当前f[i-1]是下一次的f[i-2]

我们可以举一反三
例如推一个3阶的递推式
在这里插入图片描述

然后发挥你三岁时的智商找规律
可以发现
相乘矩阵是一个(n+1)* (n+1)的矩阵
除了第i-n项对下一次没有贡献
别的都要保留
下一次的f[i-1]即本次所有项乘其系数的积
最后还要保留常数


代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int mo=9973;
struct lzf{
    
    
	long long n,m,h[100][100]; 
}a,b,x;
long long n,k;
lzf operator * (lzf l,lzf y)
{
    
    
	x.n=l.n,x.m=y.m;
	memset(x.h,0,sizeof(x.h));
	for (int i=1;i<=x.n;i++)
	    for (int k=1;k<=l.m;k++)
	        for (int j=1;j<=x.m;j++)
	             x.h[i][j]=(x.h[i][j]+l.h[i][k]*y.h[k][j]%mo)%mo;
	return x;
}
void power(long long n)
{
    
    
	 while (n)
	 {
    
    
	       if (n & 1) a=a*b;
	       b=b*b;
	       n>>=1;
	 }
}
int main()
{
    
    
	scanf("%lld%lld",&n,&k);
	b.n=n+1,b.m=n+1;
	for (int i=1;i<=n-1;i++)
	    b.h[i+1][i]=1;
	b.h[n+1][n+1]=1;  //常数保留
	for (int i=1;i<=n+1;i++)
	    scanf("%lld",&b.h[i][n]);  //前n项
	//预处理相乘矩阵
	a.n=1,a.m=n+1;
	for (int i=1;i<=n;i++)
	    scanf("%lld",&a.h[1][i]);  //前n项的系数
	a.h[1][n+1]=1;  //常数直接保留 
	//预处理答案矩阵
    power(k);  //不用减1,输入的第一项是第0项
    printf("%lld",a.h[1][1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45621109/article/details/111400138