TZOJ-4954. 矩阵游戏

🔗https://www.tzcoder.cn/acmhome/problemdetail.do?method=showdetail&id=4954

解析

首先我们需要输入N与M,然而因为数据过于大,我们就需要用字符串读入,通过取模后完成数据的输入

ll qz(string s,int x)
{
    ll aa=0;
    for (int i=0;i<s.size();i++)
    {
        aa=(aa*10+(s[i]-'0'))%x;
    }
    return aa;
}

这道题等价于求 (A^(m−1)*B)^(n−1)*A^(m−1)。

可以直接用高精度的矩阵快速幂。

不难发现在计算过程中矩阵一定是 B[0][0]=a; B[1][0]=b; B[0][1]=0; B[1][1]=1;的形式。

所以现在问题转化为了计算型为B[0][0]=a; B[1][0]=b; B[0][1]=0; B[1][1]=1;的矩阵快速幂。

矩阵的快速幂又可以体现成矩阵乘再加上快速幂

固可以推出

 f[n][m]=A*(B^{m-1}*C)^{n-1}*B^{m-1};

 矩阵快速幂
void cc(ll a[2][2],ll b[2][2])
{
    ll res[2][2];
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            res[i][j]=0;
            for(int k=0;k<2;k++)
                res[i][j]=(res[i][j]+a[i][k]*b[k][j])%MOD;
        }
    }
    for (int i=0;i<2;i++)
    {
        for (int j=0;j<2;j++)
            a[i][j]=res[i][j];
    }
}

while(m)
    {
        if (m&1)
            cc(D,B);
        cc(B,B);
        m>>=1;
    }
注意

当这里的a或c等于一时要加入特判,

a^b % p 在b远大于a的时候可以先用b = b%(p-1), 

不过在a为1的时候还是%p;

if (a==1)
        n=qz(ns,MOD);
    else
        n=qz(ns,MOD-1);
    if (c==1)
        m=qz(ms,MOD);
    else
        m=qz(ms,MOD-1);

这样就可以写出来啦

#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <set>
#include <cstring>
#include <map>
#include <stdio.h>
using namespace std;

const int MOD=1000000007;
typedef long long int ll;
string ns,ms;

ll A[2][2],B[2][2],C[2][2],D[2][2],qq[2][2];

ll qz(string s,int x)
{
    ll aa=0;
    for (int i=0;i<s.size();i++)
    {
        aa=(aa*10+(s[i]-'0'))%x;
    }
    return aa;
}

void cc(ll a[2][2],ll b[2][2])
{
    ll res[2][2];
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            res[i][j]=0;
            for(int k=0;k<2;k++)
                res[i][j]=(res[i][j]+a[i][k]*b[k][j])%MOD;
        }
    }
    for (int i=0;i<2;i++)
    {
        for (int j=0;j<2;j++)
            a[i][j]=res[i][j];
    }
}
ll n,m,a,b,c,d;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);

    cin >> ns >> ms;
    cin >> a >> b >> c >> d;
    if (a==1)
        n=qz(ns,MOD);
    else
        n=qz(ns,MOD-1);
    if (c==1)
        m=qz(ms,MOD);
    else
        m=qz(ms,MOD-1);
    m--;
    n--;
    A[0][0]=1;
    A[0][1]=1;
    A[1][1]=0;
    A[1][0]=0;

    B[0][0]=a;
    B[1][0]=b;
    B[0][1]=0;
    B[1][1]=1;

    C[0][0]=c;
    C[1][0]=d;
    C[0][1]=0;
    C[1][1]=1;

    D[0][0]=D[1][1]=1;
    D[0][1]=D[1][0]=0;

    while(m)
    {
        if (m&1)
            cc(D,B);
        cc(B,B);
        m>>=1;
    }

    qq[0][0]=D[0][0];
    qq[0][1]=D[0][1];
    qq[1][0]=D[1][0];
    qq[1][1]=D[1][1];

    cc(D,C);
    while(n)
    {
        if(n&1)
            cc(A,D);
        cc(D,D);
        n>>=1;
    }
    cc(A,qq);
    cout << A[0][0];
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值