UVA - 10870 Recurrences
题目描述
考虑递推关系式\(f(n)=a_1*f(n-1)+a_2*f(n-2)+....+a_d*f(n-d)\),计算\(f(n)\%m\)
Input
输入包含多组测试数据。每组数据第一行为三个整数\(d,n,m(1<=d<=15,1<=n<=2^{31}-1,1<=m<=46340)\)。
第二行包含\(d\)个非负整数\(a_1,a_2.....a_d\)。第三行为\(d\)个非负整数\(f(1),f(2).....f(d)\)。这些数字均不超过\(2^{31}-1\)。输入结束的标志是\(d=n=m=0\).
Output
对于每组数据,输出\(f(n)\%m\)
Sample Input
1 1 100
2
1
2 10 100
1 1
1 1
0 0 0
Sample Output
1
55
非常经典的矩阵优化递推入门题。
由题意得:有初始矩阵\(A_1\)和递推矩阵\(g\)。
\(A_1*g^{i-1}=A_i\)。
一个\(f(n)\)的值只与前\(d\)个的\(f()\)值有关,所以,我们只用构造一个\(d*d\)的矩阵。
\(g\)=\(\begin{pmatrix} a_1 & a_2 & a_3 & \cdots & a_d \\ 1 & 0 & 0 & \cdots & 0 \\ 0 & 1 & 0 & \cdots & 0 \\\vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 0 \\ \end{pmatrix},\)\(A_1\)=\(\begin{pmatrix} f_d & 0 & 0 & \cdots & 0 \\ f_{d-1} & 0 & 0 & \cdots & 0 \\ f_{d-2} & 0 & 0 & \cdots & 0 \\\vdots & \vdots & \vdots & \ddots & \vdots \\ f_1 & 0 & 0 & \cdots & 0 \\ \end{pmatrix}\)
最后,根据矩阵快速幂求解即可。
空间复杂度\(O(d^2)\),时间复杂度\(O(d^2*log_n)\)。
代码如下
#include <cstdio>
#include <cstring>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
#define LL long long
#define u64 unsigned long long
#define reg register
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(reg int i=(G).Head[x]; i; i=(G).Nxt[i])
inline int Read() {
int res = 0, f = 1;
char c;
while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
do res = (res << 3) + (res << 1) + (c ^ 48);
while (c = getchar(), c >= 48 && c <= 57);
return f ? res : -res;
}
template<class T>inline bool Min(T &a, T const&b) {return a > b ? a = b, 1 : 0;}
template<class T>inline bool Max(T &a, T const&b) {return a < b ? a = b, 1 : 0;}
const int N = 5e5 + 5, M = 25, mod = 1e9 + 9;
struct Matrix {
int Num[M][M];
inline void Init(void) {memset(Num, 0, sizeof Num);}
};
int A[M], d, n, Mod;
Matrix mul(Matrix a, Matrix b) {
Matrix Ans;
Ans.Init();
rep(k, 1, d)rep(i, 1, d)rep(j, 1, d) Ans.Num[i][j] = (Ans.Num[i][j] + (a.Num[i][k] * b.Num[k][j]) % Mod) % Mod;
return Ans;
}
inline void _main(void) {
while (~scanf("%lld %lld %lld", &d, &n, &Mod)) {
if (!d && !n && !Mod)return;
Matrix Ans, us, T;
us.Init(), Ans.Init(), T.Init();
rep(i, 1, d)us.Num[1][i] = Read();
rep(i, 2, d)us.Num[i][i - 1] = 1;
rep(i, 1, d)Ans.Num[d - i + 1][1] = Read();
rep(i, 1, d)T.Num[i][i] = 1;
if (n <= d) {
printf("%lld\n", Ans.Num[d - n + 1][1]);
continue;
}
n = n - d;
while (n) {
if (n & 1)T = mul(T, us);
us = mul(us, us);
n >>= 1;
}
Ans = mul(T, Ans);
printf("%lld\n", Ans.Num[1][1] % Mod);
}
}
signed main() {
#define offline1
#ifdef offline
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
_main();
fclose(stdin); fclose(stdout);
#else
_main();
#endif
return 0;
}