UVA 10870 Recurrences 矩阵乘法

题目:

Consider recurrent functions of the following form:

f(n) = a1f(n − 1) + a2f(n − 2) + a3f(n − 3) + … + adf(n − d), for n > d,
where a1, a2, … , ad are 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 ≤ 2
31 − 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
1 1 100
2
1
2 10 100
1 1
1 1
3 2147483647 12345
12345678 0 12345
1 2 3
0 0 0
Sample Output
1
55
423

思路:

如同fib数列一样,求出第n项的结果,蛮力递推肯定不行的,这里我们用矩阵乘法来优化,矩阵乘法的用法参考如下:
http://blog.csdn.net/qq_27508477/article/details/47663185

这里只是做了一个延伸,把矩阵从二维变道了多维。

代码:

#include "iostream"
#include"stdlib.h"
#include"cstdio"
#include"cstring"
using namespace std;
typedef long long int lint;

lint bc=0;
lint mod=0;
lint a[20];
lint f[20];
struct matrix
{
    lint x[20][20];
};

matrix mut_matrix(matrix a,matrix b)
{
    matrix temp;
    memset(temp.x,0,sizeof(temp.x));
    for(lint i=1; i<=bc; i++)
    {
        for(lint j=1; j<=bc; j++)
        {
            for(lint k=1; k<=bc; k++)
            {
                temp.x[i][j]=((a.x[i][k]%mod)*(b.x[k][j])%mod)%mod+temp.x[i][j];
                temp.x[i][j]%=mod;
            }
        }
    }
    return temp;
}

matrix pow_matrix(matrix a,lint b)
{
    matrix ans;
    memset(ans.x,0,sizeof(ans));
    for(lint i=1; i<=bc; i++)
        ans.x[i][i]=1;
    while(b)
    {
        if(b%2==1) ans=mut_matrix(ans,a);
        a=mut_matrix(a,a);
        b=b/2;
    }
    return ans;
}



int main()
{
    lint n; //求fn
    //freopen("in.txt","r",stdin);
    while(scanf("%lld %lld %lld",&bc,&n,&mod)!=EOF)
    {
        if(bc==0&&n==0&&mod==0)    break;
        matrix st;
        matrix tp;
        memset(st.x,0,sizeof(st.x));
        memset(tp.x,0,sizeof(tp.x));

        for(lint i=1; i<=bc; i++)
        {
            scanf("%Illd",&a[i]);
        }
        for(lint i=1; i<=bc; i++)
        {
            scanf("%lld",&f[i]);
        }
        for(lint i=1; i<=bc; i++)
        {
            tp.x[1][i]=a[i];
        }
        for(lint i=1; i<=bc-1; i++)
        {
            tp.x[i+1][i]=1;
        }
        for(int i=1; i<=bc; i++)
        {
            st.x[i][1]=f[bc-i+1];
        }
        if(n<=bc)   printf("%lld\n",f[n]);
        else
        {
            matrix tt=pow_matrix(tp,n-bc);
            matrix ans=mut_matrix(tt,st);
            printf("%lld\n",ans.x[1][1]);
        }
    }
    return 0;
}

最简单的就是拿fib数列去做测试证明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值