generator 1

题目链接
牛客多校第五场的B
题目大意就是给出x_{i} = a*x_{i - 1} + b* x_{i - 2} 求出 x_{n} n巨大 为10^{1000000} 给出a ,b ,x_{0},x_{1} 求 x_{n}

没想到怎么写。。

其实我们要求出一个数的话不止可以二进制拆分,还可以直接十进制拆分,二进制拆分就是普通的快速幂,x^{n} = x^{n/2} * x^{n/2} (n为偶数),为偶数),奇数时直接多乘一个x,那么什么是十进制拆分呢。例如 我们求3^{1234}如何求呢,我们可以先预处理出 3的1~10次方,然后定义ans = 1,那么3^{1234} = (((ans*3^{1})^{10}*3^2)^{10}*3^{3})^{10}*3^4,所以 我们直接遍历幂次,每次将ans变成10次方乘上当前数的x次方

那么矩阵的话就很好求出来

\begin{pmatrix} a &b \\ 1&0 \end{pmatrix}^{n - 1}*\bigl(\begin{smallmatrix} x_{1}\\ x_0 \end{smallmatrix}\bigr)

求出矩阵就为

\bigl(\begin{smallmatrix} x_{n }\\ x_{n - 1} \end{smallmatrix}\bigr)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 10;
ll MOD;
struct matrix
{
    ll m[MAXN][MAXN];
};

matrix mul(matrix m1, matrix m2, ll N)
{
    ll i, j, k;
    matrix m3;
    m3.m[0][0] = m3.m[0][1] = m3.m[1][1] = m3.m[1][0] = 0;
    for(i = 0; i < N; i ++){
        for(k = 0; k < N; k ++){
            if(m1.m[i][k] == 0)
                continue;
            for(j = 0; j < N; j ++){
                m3.m[i][j] = (m1.m[i][k] * m2.m[k][j]  + m3.m[i][j]) % MOD;//不要取太多MOD
            }
        }
    }
    return m3;
}

matrix Pow(matrix m, ll N, ll n)
{
    matrix ans;
    ans.m[0][0] = ans.m[0][1] = ans.m[1][1] = ans.m[1][0] = 0;
    for(ll i = 0; i < N; i ++)
        ans.m[i][i] = 1;
    while(n){
        if(n % 2 == 1){
            ans = mul(ans, m, N);
        }
        n /= 2;
        m = mul(m, m, N);
    }
    return ans;
}

matrix T[11];
matrix y;
matrix x;
matrix m;
char n[1000005];
int main()
{
    ll a ,b, x0, x1;
    scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b);
    scanf("%s%lld",n,&MOD);
    
    x.m[0][0] = a;
    x.m[0][1] = b;
    x.m[1][0] = 1;
    x.m[1][1] = 0;

    for(int i = 0; i <= 10; i ++){
        T[i] = Pow(x,2, i);
    }
    
    m.m[0][0] = 1;
    m.m[1][1] = 1;
    int len = strlen(n);

    for(int i = 0; i < len; i ++){
        m = Pow(m, 2, 10);
        m = mul(m , T[n[i] - '0'],2);
    }
    
    y.m[0][0] = x1;
    y.m[1][0] = x0;
    y = mul(m , y ,2);
    printf("%lld\n",y.m[1][0]);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值