Hoj 2930 Perfect Fill II

题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2930

本题是处理线性递推。

递推式:f[i] = 2*f[i-1] + f[i-3];

求线性递推问题可以转换为矩阵运算:

出任何一个线性递推式的第n项,其对应矩阵的构造方法为:在右上角的(n-1)*(n-1)的小矩阵中的主对角线上填1,矩阵第n行填对应的系数,其它地方都填0。例如,我们可以用下面的矩阵乘法来二分计算f(n) = 4f(n-1) - 3f(n-2) + 2f(n-4)的第k项:


a,b,c,d的顺序为项数的从低到高。

对于本题的递推式,f[i] = 2*f[i-1] + f[i-3];

我们可以构造连乘矩阵:

A= [0 1 0

0 0 1

1 0 2],

B = [f[0]

f[1]

f[2]]

则第n项f[n] = A^(n-2) * B.

另外用到矩阵的快速幂运算,用二分法就行了。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

#define max 3
struct Matrix
{
    int data[max][max];
};

Matrix A,B;
int n = 3;
int mod = 2010;

void init()
{
    memset(A.data,0,sizeof(A.data));
    memset(B.data,0,sizeof(B.data));
    A.data[0][1] = 1;
    A.data[1][2] = 1;
    A.data[2][0] = 1;
    A.data[2][2] = 2;
    B.data[0][0] = 1;
    B.data[1][0] = 1;
    B.data[2][0] = 2;
}
//矩阵相乘
Matrix mul(Matrix u,Matrix v)
{
    Matrix t;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            t.data[i][j] = 0;
            for(int k=0;k<n;k++)
            {
                t.data[i][j] += (u.data[i][k] * v.data[k][j])%mod;
                t.data[i][j] %= mod;
            }
        }
    }
    return t;
}
//矩阵的幂
Matrix power(Matrix matrix,int k)
{
    int k_temp = k;
    Matrix result,a;

    memset(result.data,0,sizeof(result.data));

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            a.data[i][j] = matrix.data[i][j];
            if(i == j)
            {
                result.data[i][j] = 1;
            }
            //printf("%d ",a.data[i][j]);
        }
        //printf("\n");
    }
    while(k_temp)
    {
        if(k_temp&1)
        {
            result = mul(result,a);
        }
        a = mul(a,a);
        k_temp = k_temp>>1;
    }
    return result;

}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int num;
    init();
    while(scanf(" %d",&num)!=EOF)
    {
        if(num == 1) printf("1\n");
        else if(num == 2) printf("2\n");
        else
        {
            Matrix temp = power(A,num - 2);
            Matrix fin = mul(temp,B);
            printf("%d\n",fin.data[2][0]);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值