UVa 10870 - 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 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;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值