2019牛客暑期多校训练营(第五场)generator 1(大数 矩阵快速幂 优化)

原题: https://ac.nowcoder.com/acm/contest/885/B

题意:

给出 x 0 , x 1 , a , b x_0,x_1,a,b x0,x1,a,b x i = a x i − 1 + b x i − 2 x_i=ax_{i-1}+bx_{i-2} xi=axi1+bxi2,现在给出 n ∈ [ 1 , 1 0 1 0 1 e 6 ] n\in[1,10^{10^{1e6}}] n[1,10101e6],求 x n x_n xn

解析:

以为java的BigInteger转成二进制(.toString(2))很快,没想到TLE了。可以参考参考

import java.math.*;
import java.util.*;
 
public class Main {
     
 
    public static BigInteger Two=BigInteger.valueOf(2);
    public static BigInteger One=BigInteger.valueOf(1);
    public static BigInteger Zero=BigInteger.valueOf(0);
    public static BigInteger Ten=BigInteger.valueOf(10);
    public static long mod;
     
    public static long res[][]=new long[2][];
    public static long A[][]=new long[2][];
    public static long bas[][]=new long[2][];
    public static long tmp[][]=new long[2][];
 
    public static void mul_res() {
        tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                for(int k=0;k<2;k++) {
                    tmp[i][j]+=res[i][k]*A[k][j];
                    tmp[i][j]%=mod;
                }
            }
        }
 
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                res[i][j]=tmp[i][j];
            }
        }
    }
     
    public static void mul_A() {
        tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                for(int k=0;k<2;k++) {
                    tmp[i][j]+=A[i][k]*A[k][j];
                    tmp[i][j]%=mod;
                }
            }
        }
 
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                A[i][j]=tmp[i][j];
            }
        }
    }
     
    public static void mul_bas_res() {
        tmp[0][0]=tmp[0][1]=tmp[1][0]=tmp[1][1]=0;
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                for(int k=0;k<2;k++) {
                    tmp[i][j]+=bas[i][k]*res[k][j];
                    tmp[i][j]%=mod;
                }
            }
        }
 
        for(int i=0;i<2;i++) {
            for(int j=0;j<2;j++) {
                bas[i][j]=tmp[i][j];
            }
        }
    }
     
    public static void main(String args[]) {
        Scanner cin=new Scanner(System.in);
         
 
        long x0,x1,a,b;
        x0=cin.nextInt();
        x1=cin.nextInt();
        a=cin.nextInt();
        b=cin.nextInt();
        BigInteger n;n=cin.nextBigInteger();
        mod=cin.nextInt();
        String bit=n.toString(2);
        int len=bit.length();
 
       // System.out.println(bit);
         
 
        res[0]=new long[2];
        res[1]=new long[2];
        A[0]=new long[2];
        A[1]=new long[2];
        bas[0]=new long[2];
        bas[1]=new long[2];
        tmp[0]=new long[2];
        tmp[1]=new long[2];
         
        res[0][0]=res[1][1]=1;
        res[0][1]=res[1][0]=0;
         
        bas[0][0]=x1;bas[0][1]=x0;
        bas[1][0]=bas[1][1]=0;
         
        A[0][0]=a;A[0][1]=1;
        A[1][0]=b;A[1][1]=0;
         
         
        for(int i=len-1;i>=0;i--) {
            if(bit.charAt(i)=='1') {
                mul_res();
            }
            mul_A();
        }
         
        mul_bas_res();
         
             
        System.out.println(bas[0][1]);
    }
}

后来想到预处理出每个 1 0 k 10^k 10k次的结果,预处理到 1 0 1 0 1 e 6 10^{10^{1e6}} 10101e6。又或者可以再优化一下,每 1 e 8 1e8 1e8作为一个单位,那么直接按照十进制拆开就行。

代码:

#include
#include
#include
#define LL long long
#define N 2
using namespace std;
LL MOD;
const int maxn=1e6+5;
 
struct matrix{
    int size;
    LL mat[N][N];
    matrix(int s=2){
        size=s;for(int i=0;i<s;i++)for(int j=0;j<s;j++)mat[i][j]=0;
    }
    matrix operator * (const matrix & x)const{
        matrix ans(x.size);
        for(int i=0;i<x.size;i++){
            for(int j=0;j<x.size;j++){
                for(int k=0;k<x.size;k++){
                    ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*x.mat[k][j])%MOD;
                }
            }
        }return ans;
    }
} ;
matrix swift(matrix a,LL t){
    matrix ans(a.size);
    for(int i=0;i<a.size;i++)ans.mat[i][i]=1;
    while(t){
        if(t&1ll)ans=ans*a;
        a=a*a;t>>=1;
    }return ans;
}
 
char x[maxn];
matrix mul[maxn];
 
int main(){
    int x0,x1,a,b;scanf("%d%d%d%d",&x0,&x1,&a,&b);
    scanf("%s",x);
    int len=strlen(x);
    scanf("%lld",&MOD);
    matrix bas;
 
    bas.mat[0][0]=x1,
    bas.mat[0][1]=x0,
    mul[0].mat[0][0]=a,
    mul[0].mat[1][0]=b,
    mul[0].mat[0][1]=1;
 
const int LEN=8;
    for(int i=LEN;i<=1e6+1;i+=LEN){
        mul[i]=swift(mul[i-LEN],100000000ll);
    }
 
 
    matrix ans;
    for(int i=0;i<2;i++)ans.mat[i][i]=1;
    for(int i=len-1;i>=0;i-=LEN){
        int num=0;
        for(int j=0,k=1;j<LEN;j++,k*=10){
            if(i-j<0)break;
            num+=(x[i-j]-'0')*k;
        }
        if(num==0)continue;
        ans=ans*swift(mul[len-1-i],num);
    }
    bas=bas*ans;
    printf("%lld\n",bas.mat[0][1]);
}

你可能感兴趣的:(2019牛客暑期多校训练营(第五场)generator 1(大数 矩阵快速幂 优化))