NYOJ301递推求值 NYOJ 1000又见斐波那契数列(矩阵快速幂)

矩阵快速幂的递推方面的应用(重要的应用之一); 矩阵快速幂中最重要的是矩阵的构造。构造的矩阵都是方阵, 只有方阵才能快速相乘。

NYOJ 301 递推求值

 题目连接:http://acm.nyist.net/JudgeOnline/problem.php?pid=301

由题意的递推式可知,我们构建这样的矩阵相乘的递推式

                                                     | b, 1, 0 |

    |F(N-1), F(N-2), c| * | a, 0, 0 |  = |F(N), F(N-1), c| ;

                                    | 1, 0, 1 |

   可以得到   

                                                             | b, 1, 0 |   ^ n-2

    |F(N), F(N-1), c|= |F(2), F(1), c|   *   | a, 0, 0 |             ;

                                                             | 1, 0, 1 |

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 3;
const int mod = 1000007;
int f1, f2, a, b, c, n;
struct Node
{
    int row, cal;
    int s[N][N];
    Node()
    {
        row = cal = 3;
        s[0][0] = b, s[0][1] = 1, s[0][2] = 0;
        s[1][0] = a, s[1][1] = 0, s[1][2] = 0;
        s[2][0] = 1, s[2][1] = 0, s[2][2] = 1;
    }
};
Node mem(Node x, int c)
{
    for(int i = 0; i < N; i++)
        for(int j = 0; j < N; j++)
           x.s[i][j] = c;
    return x;
}
Node Matble(Node x, Node y)
{
    Node ans;
    ans.row = x.row;
    ans.cal = y.cal;
    ans = mem(ans, 0);
    for(int i = 0; i < ans.row; i++)
        for(int j = 0; j < ans.cal; j++){
           for(int k = 0; k < x.cal; k++)
                   ans.s[i][j] = (int)(ans.s[i][j] + (long long)x.s[i][k] * y.s[k][j] % mod + mod) % mod;
    return ans;
}
int pow_Matble(int n)
{
    if(n == 1)
        return f1;
    else if(n == 2)
        return f2;
    n -= 2;
    Node ans, temp;
    ans.row = 1;
    ans.cal = 3;
    ans.s[0][0] = f2, ans.s[0][1] = f1, ans.s[0][2] = c;
    while(n > 0)
    {
        if(n%2 == 1)
            ans = Matble(ans, temp);
        temp = Matble(temp, temp);
        n /= 2;
    }
    return ans.s[0][0];
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d%d%d%d", &f1, &f2, &a, &b, &c, &n);
        printf("%d\n", pow_Matble(n));
    }
    return 0;
}

NYOJ1000  又见斐波那契数列

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=1000

本题就是斐波那契数列的加强版, 首先我们化简递推式, 我们发现F(n) = F(1)^m1 * F(0)^M0;而m1, m0, 就是斐波那契数列, 所以我们用矩阵快速幂求出m1, m0; 最用快速幂求出F(1)^m1 和F(0)^m0, 然后再相乘。

这道题让求的是F(n)对1000000007; 所以我们在用费马小定理就解决了, 费马小定理是指 ( a^p-1 )%p = 1(a, p互素);我们可以简单理解为

(a^m)%p = ( a^ (m % (p-1) ) )%p ; 这样就解决这道题了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 2;
const int mod = 1000000007;
struct Node
{
    int row, cal;
    int s[maxn][maxn];
    Node()
    {
        row = cal = 2;
        s[0][0] = 1, s[0][1] = 1;
        s[1][0] = 1, s[1][1] = 0;
    }
};
Node Matble(Node x, Node y)
{
    Node ans;
    ans.row = x.row;
    ans.cal = y.cal;
    for(int i = 0; i < ans.row; i++)
        for(int j = 0; j < ans.cal; j++)
            ans.s[i][j] = 0;
    for(int i = 0; i < ans.row; i++)
        for(int j = 0; j < ans.cal; j++)
            for(int k = 0; k < x.cal; k++)
               ans.s[i][j] = (int)(ans.s[i][j] + (long long)x.s[i][k] * y.s[k][j] % (mod-1)) % (mod-1);
    return ans;
}
void pow_Matble(int n, int& m0, int& m1)//快速幂(矩阵的)
{
    if(n == 0)
    {
        m0 = 1;
        m1 = 0;
        return ;
    }
    Node ans, temp;
    ans.row = 1, ans.cal = 2;
    ans.s[0][0] = 1, ans.s[0][1] = 0;
    n -= 1;
    while(n > 0)
    {
        if(n&1)
            ans = Matble(ans, temp);//调用矩阵乘法
        temp = Matble(temp, temp);//调用矩阵乘法
        n /= 2;
    }
    m1 = ans.s[0][0]; m0 = ans.s[0][1];
}
int pow_mod(int k, int m)//快速幂 (整数的)
{
    int ans = 1, temp = k;
    while(m > 0)
    {
        if(m&1)
            ans = (int)((long long)ans * temp % mod);
        temp = (int)((long long)temp * temp % mod);
        m /= 2;
    }
    return ans;
}
void solve(int a, int b, int n)
{
    int m0, m1;
    pow_Matble(n, m0, m1);
    int ans1 = pow_mod(a, m0);
    int ans2 = pow_mod(b, m1);
    int ans = (long long)ans1 * ans2 % mod;
    printf("%d\n", ans);
}
int main()
{
     int a, b, n;
     while(~scanf("%d%d%d", &a, &b, &n))
     {
         solve(a, b, n);
     }
     return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值