2019牛客暑期多校5B:generator 1【广义斐波拉契数列循环节模板】

题目:

2019牛客暑期多校训练营5B:generator 1

题意:

Fn = aFn-1 + bFn-2 ,给出Fn数列的前两项F0和F1,求Fn【n大到要用字符串输入】

笔记:

(1)十进制矩阵快速幂

递推式直接给出了,但N大的我不敢写矩阵快速幂,赛后了解到十进制矩阵快速幂,原理和二进制一样:比如求矩阵A^123,等价于计算:A^100 * A^20 * A^3 = (A^100)^1 * (A^10)^2 * (A^1)^3,括号里的就和二进制每次平方是一样的道理

代码:

#include 
 
#define sz(x) (x).size()
using namespace std;
typedef long long ll;
struct matrix{
    ll m[2][2];
};
matrix I = {1,0,0,1};
ll x0,x1,a,b,mod;
string s;
inline matrix operator * (const matrix &A,const matrix &B){
    matrix res;
    res.m[0][0] = (A.m[0][0]*B.m[0][0]+A.m[0][1]*B.m[1][0])%mod;
    res.m[0][1] = (A.m[0][0]*B.m[0][1]+A.m[0][1]*B.m[1][1])%mod;
    res.m[1][0] = (A.m[1][0]*B.m[0][0]+A.m[1][1]*B.m[1][0])%mod;
    res.m[1][1] = (A.m[1][0]*B.m[0][1]+A.m[1][1]*B.m[1][1])%mod;
    return res;
}
matrix qpow(matrix A,int x){
    matrix res = I;
    while(x){
        if(x&1) res = A*res;
        A = A*A;
        x >>= 1;
    }
    return res;
}
ll solve(){
    matrix A = {a,b,1,0},B = {x1,0,x0,0};
    for(int i = sz(s)-1; ~i; --i){
        if(s[i]-'0'){
           matrix t = qpow(A,s[i]-'0');
           B = t*B;
        }
        A = qpow(A,10);        
    }
    return B.m[1][0];
}
int main(){
    cin >> x0 >> x1 >> a >> b >> s >> mod;
    cout << solve() << '\n';
    return 0;
}

(2)找广义斐波拉契数列F[n]=aF[n-1]+bF[n-2]在模mod意义下的循环节

找循环节的方法来自:广义斐波拉契数列循环节

这里就存个板子(估计以后也用不上)

代码:

#include 
 
#define sz(x) (int)(x).size()
using namespace std;
typedef unsigned long long LL;
const int maxn = 1e4+15;
struct matrix{
    LL m[2][2];
};
matrix I = {1,0,0,1};
LL x0,x1,a,b,mod,prime[maxn],num[maxn];
string s;
LL qmul(LL a,LL b,LL mod){
    LL res = 0;
    while(b){
        if(b & 1) res = (res + a) % mod;
        a = (a + a) % mod; 
        b >>= 1;
    }
    return res;
}
LL qpow(LL a,LL x,LL mod){
    LL res = 1; a %= mod;
    while(x){
        if(x&1) res = res*a%mod;
        a = a*a%mod;
        x>>=1;
    }
    return res;
}
int Legendre(LL a,LL p,LL mod){
    if(qpow(a,(p-1)>>1,mod)==1) return 1;
    else return -1;
}
int getPrime(LL x){
    int cnt = 0;
    for(LL i = 2;i*i<=x; ++i){
        if(x%i == 0){
            prime[cnt] = i;
            while(x%i==0) num[cnt]++,x/=i;
            cnt++;
        }
    }
    if(x>1) prime[cnt]=x,num[cnt++]=1;
    return cnt;
}
LL lcm(LL a,LL b){
    return a/__gcd(a,b)*b;
}
LL getlen(LL a,LL b,LL mod){            //得到F[n]=aF[n-1]+bF[n-2]在模mod意义下的循环节
    int cnt = getPrime(mod);
    LL res = 1,c = a*a+4*b;
    for(int i = 0;i < cnt; ++i){
        LL p = 1;
        if(prime[i] == 2) p = 12;
        else if(c%prime[i] == 0) p = prime[i]*(prime[i]-1);
        else if(Legendre(c,prime[i],prime[i])==1) p = prime[i]-1;
        else p = (prime[i]-1)*(prime[i]+1);
        for(int j = 1;j < num[i]; ++j) p *= prime[i];
        res = lcm(res,p);
    }
    return res;
}
inline matrix operator * (const matrix &A,const matrix &B){
    matrix res;
    res.m[0][0] = (A.m[0][0]*B.m[0][0]+A.m[0][1]*B.m[1][0])%mod;
    res.m[0][1] = (A.m[0][0]*B.m[0][1]+A.m[0][1]*B.m[1][1])%mod;
    res.m[1][0] = (A.m[1][0]*B.m[0][0]+A.m[1][1]*B.m[1][0])%mod;
    res.m[1][1] = (A.m[1][0]*B.m[0][1]+A.m[1][1]*B.m[1][1])%mod;
    return res;
}
LL solve(LL x){
    matrix A = {a,b,1,0},B = {x1,0,x0,0};
    while(x){
        if(x & 1) B = A*B;
        A = A*A;
        x >>= 1;
    }
    return B.m[1][0];
}
LL cal(LL MOD){
    LL res = 0;
    for(int i = 0;i < sz(s); ++i) res = (qmul(res,10,MOD)+(s[i]-'0'))%MOD;
    return res;
}
int main(){
    cin >> x0 >> x1 >> a >> b >> s >> mod;
    cout << solve(cal(getlen(a,b,mod))) << '\n';
    return 0;
}

 

 

你可能感兴趣的:(2019牛客暑假多校训练营,模板)