Time Limit: 3000MS | Memory Limit: Unknown | 64bit IO Format: %lld & %llu |
Description
Problem A
Recurrences
Input: standard input
Output: standard output
Consider recurrent functions of the following form:
f(n) = a1 f(n - 1) + a2 f(n - 2) + a3 f(n - 3) + ... + ad f(n - d), for n > d.
a1, a2, ..., ad - arbitrary constants.
A famous example is the Fibonacci sequence, defined as: f(1) = 1, f(2) = 1, f(n) = f(n - 1) + f(n - 2). Here d = 2, a1 = 1, a2 = 1.
Every such function is completely described by specifying d (which is called the order of recurrence), values of d coefficients: a1, a2, ..., ad, and values of f(1), f(2), ..., f(d). You'll be given these numbers, and two integers n and m. Your program's job is to compute f(n) modulo m.
Input
Input file contains several test cases. Each test case begins with three integers: d, n, m, followed by two sets of d non-negative integers. The first set contains coefficients: a1, a2, ..., ad. The second set gives values of f(1), f(2), ..., f(d).
You can assume that: 1 <= d <= 15, 1 <= n <= 231 - 1, 1 <= m <= 46340. All numbers in the input will fit in signed 32-bit integer.
Input is terminated by line containing three zeroes instead of d, n, m. Two consecutive test cases are separated by a blank line.
Output
For each test case, print the value of f(n) (mod m) on a separate line. It must be a non-negative integer, less than m.
Sample Input Output for Sample Input
1 1 100 2 1 2 10 100 1 1 1 1 3 2147483647 12345 12345678 0 12345 1 2 3
0 0 0 | 1 55 423
|
Problem setter: Max Furlong
Special Thanks: Derek Kisman, EPS.
Source
Root :: Competitive Programming 2: This increases the lower bound of Programming Contests. Again (Steven & Felix Halim) :: Mathematics :: Powers of a (Square) Matrix - Standard
Root :: AOAPC I: Beginning Algorithm Contests -- Training Guide (Rujia Liu) :: Chapter 2. Mathematics :: Matrix & System of Linear Equations :: Examples
题意:
考虑线性递推关系f(n)=a1*f(n-1) + a2*f(n-2) + .. ad*f(n-d),计算f(n)
n<=2^31-1,如果直接递推肯定超时
第一次接触这种通过矩阵来快速求线性递推式的第n项,一般方式如下
设矩阵Fn = [ f(n) f(n-1) f(n-2) ... f(n-d) ]
然后构造一个矩阵(称为友矩阵或者Q矩阵)A,满足如下:
Fn-1 * A = Fn ==>
[ f(n-1) f(n-2) ... f(n-1-d) ] * A = [ f(n) f(n-1) f(n-2) ... f(n-d) ]
在Fn-1里面f(n-1)..f(n-d)都计算出来了,可以直接用,然后要通过给的条件计算出f(n),
A :
a1 1 0 0 0 0 ...
a2 0 1 0 0 0 ...
a3 0 0 1 0 0 ...
a4 0 0 0 1 0 ...
a5 0 0 0 0 1 ...
....
这个矩阵就是满足条件的矩阵
Fn = Fd * A^(n-d)
A^(n-d)可以通过矩阵快速幂来计算。
所以总的复杂度就是矩阵快速幂的复杂度 O(d^3 * log(n))
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));
const int maxn = 20;
struct Matrix {
LL e[maxn][maxn];
int n, m;
Matrix(int n=0, int m=0) : n(n), m(m) { clear(); }
void clear() {
memset(e, 0, sizeof(e));
}
};
Matrix GA;
Matrix F;
Matrix MatrixMult(Matrix a, Matrix b, int MOD) {
Matrix res(a.n, b.m);
for(int i=0; i<res.n; i++) {
for(int j=0; j<res.m; j++) {
for(int k=0; k<a.m; k++) {
res.e[i][j] = (res.e[i][j] + a.e[i][k] * b.e[k][j] ) % MOD;
}
}
}
return res;
}
Matrix MatrixPow(Matrix A, int p, int MOD) {
Matrix res(A.n, A.m);
for(int i=0; i<res.n; i++) res.e[i][i] = 1;
while(p) {
if(p & 1) res = MatrixMult(res, A, MOD);
A = MatrixMult(A, A, MOD);
p >>= 1;
}
return res;
}
int main() {
int d, n, MOD;
while(scanf("%d%d%d", &d, &n, &MOD) != EOF && (d || n || MOD)) {
GA.clear();
GA.n = GA.m = d;
F.n = 1;
F.m = d;
for(int i=0; i<d; i++) {
scanf("%lld", &GA.e[i][0]);
}
for(int i=1; i<d; i++) {
GA.e[i-1][i] = 1;
}
for(int i=d-1; i>=0; i--) {
scanf("%lld", &F.e[0][i]);
}
if(n <= d) {
printf("%lld\n", F.e[0][n-1]);
continue;
}
int p = n - d;
GA = MatrixPow(GA, p, MOD);
F = MatrixMult(F, GA, MOD);
LL ans = F.e[0][0];
printf("%lld\n", ans);
}
return 0;
}