题解:UVA10870 Recurrences
UVA10870 题解
题面
题意
考虑以下形式的递推函数:
\(f(n)=a_1f(n-1)+a_2f(n-2)+a_3f(n-3)+\cdots+a_df(n-d)\)(当 \(n>d\) 时)
其中 \(a_1,a_2,\cdots,a_d\) 是任意常数。
- 递推的阶数 \(d\)(称为递推的阶数),
- \(d\) 个系数 \(a_1,a_2,\cdots,a_d\),
- 初始值 \(f(1),f(2),\cdots,f(d)\)。
输入将给定这些数字,以及两个整数 \(n\) 和 \(m\)。程序的任务是计算 \(f(n)\) 对 \(m\) 取模的结果。
思路
这题是裸的矩阵加速。(应该没有蓝吧……)
首先我们有如下式子。
- \(f_i=a_1\times f_{i-1}+a_2\times f_{i-2}+\cdots+a_d\times f_{i-d}\)。
- \(f_{i-1}=1\times f_{i-1}+0\times f_{i-2}+\cdots+0\times f_{i-d}\)。
- \(f_{i-2}=0\times f_{i-1}+1\times f_{i-2}+\cdots+0\times f_{i-d}\)。
- \(\cdots\)
- \(f_{i-d+1}=0\times f_{i-1}+0\times f_{i-2}+\cdots+1\times f_{i-d+1}+0\times f_{i-d}\)。
把这些式子化成矩阵。
\(\begin{bmatrix}f_i\\f_{i-1}\\\cdots\\f_{i-d+2}\\f_{i-d+1}\end{bmatrix}=\begin{bmatrix}a_1&a_2&\cdots&a_{d-1}&a_d\\1&0&\cdots&0&0\\0&1&\cdots&0&0\\&&\cdots\\0&0&\cdots&1&0\end{bmatrix}\times\begin{bmatrix}f_{i-1}\\f_{i-2}\\\cdots\\f_{i-d+1}\\f_{i-d}\end{bmatrix}\)
于是要是 \(n\leqslant d\) 的话直接输出 \(f_n\),否则我们就可以用矩阵快速幂加速。
\(\begin{bmatrix}f_i\\f_{n-1}\\\cdots\\f_{n-d+2}\\f_{n-d+1}\end{bmatrix}=\begin{bmatrix}a_1&a_2&\cdots&a_{d-1}&a_d\\1&0&\cdots&0&0\\0&1&\cdots&0&0\\&&\cdots\\0&0&\cdots&1&0\end{bmatrix}^{n-d}\times\begin{bmatrix}f_{d}\\f_{d-1}\\\cdots\\f_{2}\\f_{1}\end{bmatrix}\)
注意,在输入答案矩阵的时候是倒着输入的,不要搞错了。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll k,n,mod;
class matrix{
public:
ll g[25][25];
matrix(){for(int i=0; i<k; i++) for(int j=0; j<k; j++)g[i][j]=0;}
void clear(){for(int i=0; i<k; i++) for(int j=0; j<k; j++)g[i][j]=0;}
void print(){for(int i=0; i<k; i++){for(int j=0; j<k; j++)cout<<g[i][j]<<' ';cout<<endl;}}
matrix& operator = (const matrix& x){for(int i=0; i<k; i++) for(int j=0; j<k; j++) g[i][j]=x.g[i][j];return *this;}
matrix operator * (const matrix& x){matrix c;for(int i=0; i<k; i++) for(int j=0; j<k; j++) for(int l=0; l<k; l++) (c.g[i][j]+=g[i][l]*x.g[l][j]%mod)%=mod;return c;}
matrix operator ^ (const ll& x){matrix res,a=*this;ll b=x;for(int i=0; i<k; i++) res.g[i][i]=1;while(b){if(b&1)res=res*a;a=a*a;b>>=1;}return res;}
};
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
int main(){
while(1){
k=read();n=read();mod=read();
if(!k&&!n&&!mod) return 0;
matrix f,ans;
for(int i=1; i<k; i++) f.g[i][i-1]=1;
for(int i=0; i<k; i++) f.g[0][i]=read();
for(int i=k-1; ~i; i--) ans.g[i][0]=read();
if(n<=k){write(ans.g[k-n][0]%mod);putchar('\n');continue;}
f=f^(n-k);ans=f*ans;
write(ans.g[0][0]);putchar('\n');
}
}