UVA - 10870 Recurrences (矩阵快速幂)


Consider recurrent functions ofthe 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 byspecifying d (which is called the order of recurrence), values of dcoefficients: a1, a2, ..., ad, and values off(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 testcase begins with three integers: d, n, m, followed by twosets 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. Allnumbers in the input will fit in signed 32-bit integer.

Input is terminated by line containing threezeroes instead of d, n, m. Two consecutive test cases are separated by a blankline.

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.

 

SampleInput                             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: MaxFurlong

Special Thanks: DerekKisman, EPS.

题意:考虑一个递推关系 f[n] = a1*f[n-1] + a2*f[n-2] + .... ad*f[n-d],求f[n] % m

思路:和经典的Fibonacci的递推矩阵构造类似

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
using namespace std;
const int maxn = 30;

int n, m, d;
struct Matrix {
	ll v[maxn][maxn];
	Matrix() {} 
	Matrix(int x) {
		init();
		for (int i = 0; i < maxn; i++)
			v[i][i] = x;
	}
	void init() {
		memset(v, 0, sizeof(v));
	}
	Matrix operator *(Matrix const &b) const {
		Matrix c;
		c.init();
		for (int i = 0; i < d; i++)
			for (int j = 0; j < d; j++)
				for (int k = 0; k < d; k++)
					c.v[i][j] = (c.v[i][j] + (v[i][k] * b.v[k][j]) % m) % m;
		return c;
	}
	Matrix operator ^(int b) {
		Matrix tmp = *this, res(1);
		while (b) {
			if (b & 1)
				res = res * tmp;
			tmp = tmp * tmp;
			b >>= 1;
		}
		return res;
	}
} a, b, res;
ll f[maxn];

int main() {
	while (scanf("%d%d%d", &d, &n, &m) != EOF && n+m+d) {
		a.init();
		b.init();
		for (int i = 0; i < d; i++)
			scanf("%lld", &a.v[0][i]);
		for (int i = 0; i < d; i++)
			scanf("%lld", &f[i]);
		for (int i = 1; i < d; i++)
			a.v[i][i-1] = 1;

		if (n == 1) {
			printf("%lld\n", f[n-1]);
			continue;
		}

		b = a ^ (n-d);
		ll ans = 0;
		for (int i = 0; i < d; i++)
			ans = (ans + (f[d - 1 - i] * b.v[0][i]) % m) % m;

		printf("%lld\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值