UVa 10870 Recurrences
题目大意:
f(n)=a1f(n−1)+a2f(n−2)+a3f(n−3)+...+adf(n−d).
给出a1~ad,f(1)~f(d),n,
(1≤d≤15,1≤n≤231−1,1≤m≤46340)
题目分析:
若选择递推计算的话,时间复杂度为O(nd),显然会超时.
现在已知f(n)的递推式,则可以构造矩阵
A=⎡⎣⎢⎢⎢⎢⎢⎢000ad100ad−1010ad−2001...ad−3............000a1⎤⎦⎥⎥⎥⎥⎥⎥,Fn=⎡⎣⎢⎢⎢⎢⎢⎢f(n−d)...f(n−2)f(n−1)f(n)⎤⎦⎥⎥⎥⎥⎥⎥
Fn=A×Fn−1
Fn=An−d×Fd
那么现在只需要算出An−d即可,可以用快速幂加速,时间复杂度为O(d3log(n−d))
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=20;
int d,n,MOD;
struct Matrix {//定义结构体Matrix,重载乘法运算符,便于计算
int n,m;
ll M[maxn][maxn];
Matrix(){memset(M,0,sizeof(M));n=m=0;}
Matrix(int n,int m):n(n),m(m){memset(M,0,sizeof(M));}
Matrix operator * (const Matrix& rhs) const {
Matrix ret(n,rhs.m);
for(int i=1;i<=n;i++)
for(int j=1;j<=rhs.m;j++) {
for(int k=1;k<=m;k++)
ret.M[i][j]+=M[i][k]*rhs.M[k][j];
ret.M[i][j]%=MOD;
}
return ret;
}
Matrix operator *= (const Matrix& rhs) {
return *this=*this*rhs;
}
};
Matrix qpow(Matrix x,int y)//矩阵快速幂
{
Matrix ret(x.n,x.m);
for(int i=1;i<=ret.n;i++) ret.M[i][i]=1;
while(y>0) {
if(y&1) ret*=x;
x*=x;y>>=1;
}
return ret;
}
int main()
{
while(scanf("%d%d%d",&d,&n,&MOD)==3&&d) {
Matrix A(d,d),F(d,1);
for(int i=1;i<d;i++) A.M[i][i+1]=1;
for(int i=d;i>=1;i--) scanf("%lld",&A.M[d][i]),A.M[d][i]%=MOD;//注意系数a是倒着存放的
for(int i=1;i<=d;i++) scanf("%lld",&F.M[i][1]),F.M[i][1]%=MOD;
A=qpow(A,n-d);
F=A*F;
printf("%lld\n",F.M[d][1]);
}
return 0;
}