UVa 10870 - Recurrences (矩阵构造 矩阵快速幂)

来源:互联网 发布:生死手游刷金币软件 编辑:程序博客网 时间:2024/06/05 09:06

Recurrences
Time Limit: 3000MSMemory Limit: Unknown64bit IO Format: %lld & %llu

[Submit]   [Go Back]   [Status]  

Description

Download as PDF

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: dnm, 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 3: The New Lower Bound of Programming Contests (Steven & Felix Halim) :: Rare Topics :: Rare Algorithms :: Matrix Power

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

[Submit]   [Go Back]   [Status]  




题意:

考虑线性递推关系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 WINtypedef __int64 LL;#define iform "%I64d"#define oform "%I64d\n"#define oform1 "%I64d"#elsetypedef 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;}







0 0