問題描述
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;
}