• 2019牛客多校B generator 1——十进制快速幂


    题目

    已知 $x_i = ax_i + bx_{i-1}$,求 $x_n \% MOD$.($1leq nleq 10^{(10^6)}$)

    分析

    写成矩阵快速幂的形式,相当于求转移矩阵的 $n$ 次幂。

    由于 $n$ 过大,只能用字符串形式保存,如果转成二进制复杂度过高,就直接用十进制好了。

    其实十进制快速幂和二进制几乎一样,都是倍增的思想。

    ll qpow(ll a, ll b, ll p)
    {
        ll ret = 1;
        while(b)
        {
            if(b&1) ret = ret*a%p;
            a = a*a%p;
            b >>= 1;
        }
        return ret;
    }
    
    inline ll shi_pow(ll a, ll b, ll p)
    {
        ll ret = 1;
        while(b)
        {
            ll yu = b%10;
            if(yu) ret = ret*qpow(a,yu,p)%p;
            a = qpow(a, 10, p);
            b /= 10;
        }
        return ret;
    }

    二进制更快,里面能用二进制的换成了二进制。

    回到题目,将字符串 $n$ 从高到低就是十进制,与上面类似

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=1000000+10;
    ll x0,x1,a,b,mod;
    char s[N];
    
    struct Mat{
        int r,c;
        ll m[3][3];
        Mat(){
            //memset(m,0,sizeof(m));
            for(int i = 0;i < 3;i++)
                for(int j = 0;j < 3;j++)
                    m[i][j]=0;
        }
    };
    
    inline Mat mmul(Mat x,Mat y,ll p){
        Mat ans;
        ans.r=x.r;
        ans.c=y.c;
        for(int i=0;i<x.r;i++)
            for(int k=0;k<x.c;k++)
                for(int j=0;j<y.c;j++){
                    ans.m[i][j] = (ans.m[i][j] + x.m[i][k]*y.m[k][j])%p;
                }
        return ans;
    }
    
    inline Mat mpow(Mat x,ll y,ll p){
        Mat ans;
        ans.r=x.r;
        ans.c=x.c;
        for(int i=0;i<ans.c;i++) ans.m[i][i]=1;
        while(y){
            if(y&1) ans=mmul(ans,x,p);
            x=mmul(x,x,p);
            y>>=1;
        }
        return ans;
    }
    
    inline Mat m_shi_pow(Mat x,char* s,ll p){
        Mat ans;
        ans.r=x.r;
        ans.c=x.c;
        int len = strlen(s);
        for(int i=0;i<ans.c;i++) ans.m[i][i]=1;
        while(len--){
            int yu = (s[len]-'0');  //printf("yu:%d
    ", yu);
            if(yu) ans=mmul(ans,mpow(x, yu, p),p);
            x=mpow(x,10,p);
        }
        return ans;
    }
    
    int main(){
        scanf("%lld%lld%lld%lld", &x0, &x1, &a, &b);
        scanf("%s%lld", s, &mod);
        Mat A,T;
        A.r=2; A.c=1;
        A.m[0][0]=x1; A.m[1][0]=x0;
        T.r=2; T.c=2;
        T.m[0][0]=a; T.m[0][1]=b; T.m[1][0]=1; T.m[1][1]=0;
        T = m_shi_pow(T, s, mod);
        A = mmul(T, A, mod);
        printf("%lld
    ", A.m[1][0]);
    
        return 0;
    }

    这题有点卡常,加些常数优化才抖过去。

  • 相关阅读:
    CSDN的验证码,真得很糟糕
    CSDN的验证码,为什么要这样呢
    <转>http协议 文件下载原理详解
    验证码,验证码,继续
    搞了一天,气死我了
    昨天下午三点,到晚上六点写的(干死单文档)
    一个早晨加,一个上午的结果
    Linux+QT4+我忙活半宿的结果
    Linux真好玩阿,不过我家电脑不行,运行不够流畅
    springboot之整合JPA
  • 原文地址:https://www.cnblogs.com/lfri/p/11297999.html
Copyright © 2020-2023  润新知