递推数列
时间限制:1秒 空间限制:65536K 热度指数:4721
题目描述
给定a0,a1,以及an=p*a(n-1) + q*a(n-2)中的p,q。这里n >= 2。 求第k个数对10000的模。
输入描述:
输入包括5个整数:a0、a1、p、q、k。
输出描述:
第k个数a(k)对10000的模。
示例1
输入
20 1 1 14 5
输出
8359
几个月前做这道题的时候,我还不知什么是矩阵快速幂;
当时只是想着简单递推的方式做,牛客网是可以AC的,但是据说递推的方法在九度OJ上Runtime Error。
于是此题就变成一道裸的矩阵快速幂模板题,关键在于递推矩阵的构造。
递推法
#include <iostream>
#include<cstring>
using namespace std;
const int nmax=1e4;
int a[nmax];
int main(int argc, char** argv) {
int a0,a1;
int p,q,k;
int ans;
while(cin>>a0>>a1>>p>>q>>k){
memset(a,0,sizeof(a));
a[0]=a0;a[1]=a1;
for(int i=2;i<=k;i++){
a[i]=(p*a[i-1]+q*a[i-2])%10000;
}
ans=a[k];
cout<<ans<<endl;
}
return 0;
}
矩阵快速幂
当n很大时,只能采用矩阵快速幂了。
本题中初始矩阵、递推矩阵如下:
AC Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll nmax=3;
const ll MOD=10000;
#define mod(x) ((x)%MOD)
int n;
struct mat{
ll m[nmax][nmax];
}unit;
//A*B^(n-2)=C //C矩阵的首项即为f(n)
mat operator *(mat a,mat b){
mat ret;
ll x;
for(ll i=0;i<nmax;i++){//3*3
for(int j=0;j<nmax;j++){
x=0;
for(ll k=0;k<nmax;k++){
x+=mod((ll)a.m[i][k]*b.m[k][j]);
}
ret.m[i][j]=mod(x);
}
}
return ret;
}
void init_unit(){
for(ll i=0;i<nmax;i++){
unit.m[i][i]=1;
}
return;
}
mat pow_mat(mat a,ll n){//求矩阵a的n次幂
mat ret=unit;
while(n){
if(n&1) ret=ret*a;
a=a*a;
n>>=1;
}
return ret;
}
int main(int argc, char** argv) {
ll a0,a1,p,q,k;
init_unit();
while(cin>>a0>>a1>>p>>q>>k){
if(k==0) printf("%lld\n",mod(a0));
else if(n==1) printf("%lld\n",mod(a1));
else{
mat a,b;
ll a2=p*a1+q*a0;
//cout<<a1<<" "<<a0<<" "<<p<<" "<<q<<" "<<k<<endl;
//cout<<a2<<endl;
b.m[0][0]=p;b.m[0][1]=1;b.m[0][2]=0;
b.m[1][0]=q;b.m[1][1]=0;b.m[1][2]=1;
b.m[2][0]=0;b.m[2][1]=0;b.m[2][2]=0;
a.m[0][0]=a2;a.m[0][1]=a1;a.m[0][2]=a0;
a.m[1][0]=0; a.m[1][1]=0; a.m[1][2]=0;
a.m[2][0]=0; a.m[2][1]=0; a.m[2][2]=0;
b=pow_mat(b,k-2);
a=a*b;
//printf("%lld\n",mod(a.m[0][0]));
printf("%lld\n",a.m[0][0]%MOD);
}
}
return 0;
}