Fzoj 1692 Problem 1692 Key problem [特殊矩阵的n^2复杂度求矩阵乘法]

题目链接:acm.fzu.edu.cn/problem.php?pid=1692

题目的意思比较简单。。。

说是,n个小孩围成一圈。。。。(n最大100)。。初始时,每个小孩有ai个苹果。。对于每轮游戏,第i个小孩可以再获得他左边的L倍 + 他右边的 R倍个苹果。。。。问m轮游戏以后。。每个小孩有多少个苹果。。。最后mod一个数。。(m <= 10^9)。。。。

一直推样例。。。没过。。。。。样例都推不出来。。。囧。。。

后来试试 他左边的R倍 + 右边的L倍。。。。样例出来了。。。你逗我们呢???好吧。。.

矩阵快速幂。。。。。。。。。这是一开始的想法。。。水之????

果断的TLE了。。。。。。- - 。。0.0 还有更加优化的方法???好吧。。又 学习了。。。

学习了一种特殊矩阵乘法的n^2复杂度。。。

比如这个问题。。。

我们可以构造出状态转移矩阵。。。很easy。。。。。。

比如  n  =  5的时候。。我们的状态转移矩阵为:

A = {

    1  R  0 0 L

    L  1  R 0 0

    0  L 1  R 0

    0  0  L 1 R

    R 0  0  L 1

};

这是我们的状态转移矩阵。。。。。。。。。

我们可以发现

A^2 = {

    2RL    2R    R^2    L^2     2L

    2L      2RL    2R    R^2    L^2

    L^2    2L     2RL    2R     R^2

    R^2   L^2    2L     2RL    2R 

    2R    R^2   L^2     2L      2RL

};

也就是说,我们可以通过推出第一层。。。。然后从第一层推出第二层。。。。。这样就可以为n^2的时间复杂度了求出矩阵乘法了。。。。比较特殊的是,这种做法,只能用于这种特殊的矩阵。。。。所以,对于广泛性上,还需要很大的提高。。。!!

Code:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long

const int N = 105;
LL n, m, L, R, mod;
LL a[N];
struct Matrix
{
    int n, m;
    LL mi[N][N];
    void CLR(){
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= m; j ++)
            mi[i][j] = 0;
        }
    }
    void Unit(){
        for(int i = 1; i <= n; i ++){
            mi[i][i] = 1;
        }
    }
} A, ans;

Matrix operator * (Matrix a, Matrix b)
{
    Matrix tmpans;
    tmpans.n = a.n; tmpans.m = b.m;
    tmpans.CLR();
    for(int i = 1; i <= a.m; i ++){
        for(int j = 1; j <= b.n; j ++)
        tmpans.mi[1][i] = (tmpans.mi[1][i] + a.mi[1][j] * b.mi[j][i]) % mod;
    }
    for(int i = 2; i <= a.n; i ++){
        tmpans.mi[i][1] = tmpans.mi[i - 1][a.n];
        for(int j = 2; j <= b.n; j ++){
            tmpans.mi[i][j] = tmpans.mi[i - 1][j - 1];
        }
    }
    return tmpans;
}

void power(LL k)
{

    while(k){
        if(k & 1) ans = ans * A;
        A = A * A;
        k = k >> 1;
    }
}

int main()
{
//    freopen("1.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T --){
        scanf("%I64d %I64d %I64d %I64d %I64d", &n, &m, &L, &R, &mod);
        ans.n = 1; ans.m = n;
        for(int i = 1; i <= n; i ++){
            scanf("%I64d", &ans.mi[1][i]);
        }
        A.n = n; A.m = n;
        A.CLR();
        A.mi[n][1] = R;
        for(int i = 1; i <= n; i ++){
            A.mi[i - 1][i] = R;
            A.mi[i][i] = 1;
            A.mi[i + 1][i] = L;
        }
        A.mi[1][n] = L;
        power(m);
        for(int i = 1; i <= n; i ++){
            printf("%I64d%c", ans.mi[1][i] % mod, i == n ? '\n' : ' ');
        }
    }
    return 0;
}

表示,又长知识了。。。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值