问题描述
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 的数值大小。
Sample input
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
Sample output
45
104
解题思路
首先看一下这个函数的线性递推式:
注意k的取值范围是k < 2e9,如果我们单纯用线性递推式来做,无法再1s中得到结果,联想到矩阵快速幂可以用来求解线性递推公式,因此我们使用矩阵快速幂来做。
构造的转移矩阵如下所示:
根据这个转移矩阵结合矩阵快速幂,可以将时间复杂度降低到。
完整代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=11;
struct Matrix{
Matrix(int _size=0) {
Size=_size; mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
mat[i][j]=0;
}
Matrix(const Matrix& t){
Size=t.Size; mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
memcpy(mat,t.mat,sizeof(mat));
}
~Matrix(){
for (int i=0; i<Size; i++) delete[] mat[i];
delete[] mat;
}
Matrix operator*(const Matrix& t) const{
Matrix ret(Size);
for (int i=0; i<Size; ++i)
for (int j=0; j<Size; ++j)
for (int k=0; k<Size; ++k)
ret.mat[i][j]+=mat[i][k]*t.mat[k][j];
return ret;
}
Matrix operator%(const int m) const {
Matrix ret(Size);
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
ret.mat[i][j]=mat[i][j]%m;
return ret;
}
Matrix& operator=(const Matrix& t){
for (int i=0; i<Size; i++) delete[] mat[i];
delete[] mat;
Size=t.Size;
mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
mat[i][j]=t.mat[i][j];
return *this;
}
void quick_pow(int x,int m){//x次幂模m
Matrix ret(Size);
for (int i=0; i<Size; i++) ret.mat[i][i]=1;
while(x){
if(x&1) {
ret=ret*(*this); ret=ret%m;
}
*this=(*this)*(*this);
*this=(*this)%m;
x>>=1;
}
*this=ret;
}
int Size;
int** mat;
};
int a[maxn],k,m;
int getint(){
int x=0,s=1; char ch=' ';
while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
return x*s;
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
while(scanf("%d %d",&k,&m)!=EOF){
if(k<10){
printf("k\n"); continue;
}
Matrix mat1(10);
for (int i=0; i<10; i++){
scanf("%d",&a[i]);
mat1.mat[0][i]=a[i];
}
for (int i=1; i<10; i++)
mat1.mat[i][i-1]=1;
mat1.quick_pow(k-9,m);
long long ans=0;
for (int i=0; i<10; i++)
ans+=mat1.mat[0][i]*(9-i);
ans%=m;
printf("%lld\n",ans);
}
return 0;
}