2019牛客暑期多校训练营(五)

声明:本文章题目来源均为牛客网

链接:https://ac.nowcoder.com/acm/contest/885#question

B-generator 1

题目链接:https://ac.nowcoder.com/acm/contest/885/B

题目类型:矩阵乘法,矩阵快速幂,十进制快速幂

题目大意

给四个正整数 X0,X1,a,b,然后有一个公式 Xi=a*Xi-1+b*Xi-2(i>2),题目给出两个正整数n和mod,然后输出Xn%mod的值,n是一个很大的数。

(1 < X0,X1,a,b < 1e9),(1e9 < mod <2e9),(2 < n < 1e1e6

题目理解

题目给了一个递推式,而且n很大,可以用矩阵来写。化成化成矩阵然后用矩阵快速幂,对于n为1e1e6,用二进制倍增是解决不了问题的,所以要用十进制倍增同时用二进制倍增优化。和二进制快速幂差不多的思想,十进制快速幂犹如将3419拆成31x9 * 310x1 * 3100x4。上个板子应该就好理解了。

typedef long long ll;
ll pow2(ll base,ll k,ll mod){//二进制 
    ll ans=1;
    while(k){
        if(k&1) ans=(ans*base)%mod;
        k>>=1;
        base=(base*base)%mod;
    }
    return ans%mod;
}
//s为用字符串存放的大数 
ll pow10(ll base,string s,ll mod){//十进制 
    ll ans=1,res=1;
    ll len=s.size();
    for(int i=len-1;i>=0;i--){
        ll k=s[i]-'0';
        res=pow2(base,k,mod);
        ans=(ans*res)%mod;
        base=pow2(base,10,mod);
    }
    return ans%mod;
}

理解了十进制快速幂,那么这题就和普通的矩阵快速幂差不多了。

AC代码

//十进制快速幂 
#include<iostream>
#include<cstdio>
#include<string>
#define ll long long 
#define sc(x) scanf("%lld",&x);
using namespace std;
ll x0,x1,a,b,mod;
string n;
struct jz{
    ll sq[2][2];
    jz(){
        sq[0][0]=1ll;sq[0][1]=0ll;sq[1][0]=0ll;sq[1][1]=1ll;
    }
};
jz mul(jz j1,jz j2){
    jz ans;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++){
            ll x=0;
            for(int k=0;k<2;k++)
                x+=((ll)j1.sq[i][k]*j2.sq[k][j])%mod;
            ans.sq[i][j]=x%mod;
        }
    return ans;
}
jz pow2(jz t,ll k){
    jz tt;
    while(k){
        if(k&1) tt=mul(tt,t);
        k>>=1;
        t=mul(t,t);
    }
    return tt;
}
jz pow10(jz t){
    jz t1,t2;
    for(int i=n.size()-1;i>=0;i--){
        ll k=n[i]-'0';
        t1=pow2(t,k);
        t2=mul(t2,t1);
        t=pow2(t,10);
    }
    return t2;
}
int main(){
    sc(x0);sc(x1);sc(a);sc(b);cin >> n;sc(mod);
    x1%=mod;x0%=mod;
    for(int i=n.size()-1;i>=0;i--){
        if(n[i]=='0')
            n[i]='9';
        else{
            n[i]=char(n[i]-1);break;
        }
    }
    jz t;
    t.sq[0][0]=a;t.sq[0][1]=1;t.sq[1][0]=b;t.sq[1][1]=0;
    t=pow10(t);
    printf("%lld",((t.sq[0][0]*x1)%mod+(t.sq[1][0]*x0)%mod)%mod);
    return 0;
}

后记

这道题不难。不知道10进制快速幂的话就另说。

原文地址:https://www.cnblogs.com/lastonepersonwhohavebitenbycompanies/p/11288719.html