牛客 - 牛牛的斐波那契字符串

题目描述

牛牛的斐波那契字符串

解法:(C++)

详细参考 __CYJian__的解

先来枚举一下

A A A
B B B
A B AB AB
B A B BAB BAB
A B B A B ABBAB ABBAB
B A B A B B A B BABABBAB BABABBAB
⋯ ⋯ \cdots \cdots

其实,很容易想到,如果 S S S 只存在 A A A B B B 中,而不在交接处的话,工作量会小很多,就只是递推式的问题

当然情况没有那么简单,但是我们看一下交接处是什么样的呢? A B AB AB B A BA BA B B BB BB,如果我们能够知道每个交接处出现了几次 S S S 那问题就还是递推了

也就是说整的任务就两件事:

  • 计算 A A A B B B A B AB AB B A BA BA B B BB BB S S S 出现的次数
  • 计算 f i b s t r n fibstr_n fibstrn A A A B B B A B AB AB B A BA BA B B BB BB 出现的次数

下面我们讲一些细节上的内容:

S S S 出现的次数可以用 KMP 算法, KMP()函数仅是计算了失配数组,Calc() 完成具体出现次数的计算

关于递推,我们可以利用矩阵的的知识,具体如引用博客中所述,但是关于关于矩阵计算的式子要跟正一下是 F i + 1 = A × F i − 1 , i > 2 F_{i+1}= A \times F_{i-1}, i>2 Fi+1=A×Fi1,i>2

最后就是一些程序上的问题,我们在这里一并讲了:

对于程序中的任何一个位置, T [ . . . ] T[...] T[...] 只是一个中间数组,在 while(n && (la 里,我们最终得到是第一组长度大于 S S S f i b s t r i fibstr_i fibstri f i b s t r i − 1 fibstr_{i-1} fibstri1;之后,分别计算 S S S 出现次数时, T [ . . . ] T[...] T[...] 也只是暂存一下

fsp()函数中矩阵的乘法利用了快速幂的思想

#include 

using namespace std;

typedef long long ll;

const int N = 2000010;
const int MOD = 1e9+7;

char A[N], B[N], S[N], T[N];
int la, lb, ls, len, lenA, lenB, lenAB, lenBA, lenBB, res;
ll n;

struct Matrix{
    int matrix[12][12];
    int n, m;
    friend Matrix operator * (Matrix a, Matrix b){
        Matrix c;
        c.n = a.n;
        c.m = b.m;
        memset(c.matrix, 0, sizeof(c.matrix));
        for(int i=0;i<a.n;i++)
            for(int j=0;j<b.m;j++)
                for(int k=0;k<a.m;k++)
                    c.matrix[i][j] = (1LL*a.matrix[i][k]*b.matrix[k][j]+c.matrix[i][j])%MOD;
        return c;
    }
}MatrixA;

Matrix fsp(Matrix a, ll k){
    Matrix s;
    s.n = 12;
    s.m = 1;
    memset(s.matrix, 0, sizeof(s.matrix));
    if(k==0)
    {
        s.matrix[0][0] = 1;
        s.matrix[6][0] = 1;
        return s;
    }
    k--;
    s.matrix[1][0] = 1;
    s.matrix[5][0] = 1;
    s.matrix[6][0] = 1;
    s.matrix[7][0] = 1;
    s.matrix[10][0] = 1;
    while(k)
    {
        if(k&1) s = a*s;
        a = a*a;
        k >>= 1;
    }
    return s;
}

void Add(){
    // 按照斐波那契规则加和字符串
    int l = 0;
    for(int i=1;i<=la;i++) T[++l] = A[i];
    for(int i=1;i<=lb;i++) T[++l] = B[i];
    la = lb;
    for(int i=1;i<=la;i++) A[i] = B[i];
    lb = l;
    for(int i=1;i<=lb;i++) B[i] = T[i];
}

int f[N];
void KMP(int n){
    for(int i=2;i<=n;i++)
    {
        int j = f[i-1];
        while(j && S[i]!=S[j+1]) j = f[j];
        j += (S[i]==S[j+1]);
        f[i] = j;
    }
}

int Calc(int n){
    int cnt = 0;
    for(int i=1, j=0;i<=n;i++)
    {
        while(j && S[j+1]!=T[i]) j = f[j];
        j += (T[i]==S[j+1]);
        if(j==ls)
        {
            j = f[j];
            cnt++;
        }
    }
    return cnt;
}


int main()
{
    scanf("%lld%s%s%s", &n, A+1, B+1, S+1);
    n--;
    la = strlen(A+1);
    lb = strlen(B+1);
    ls = strlen(S+1);

    // A、B 的长度都小于 S
    while(n && (la<ls || lb<ls))
    {
        Add();
        n--;
    }

    KMP(ls);

    // S 在 A 中出现的次数
    len = 0;
    for(int i=1;i<=la;i++) T[++len] = A[i];
    lenA = Calc(len);

    // S 在 B 出现的次数
    len  = 0;
    for(int i=1;i<=lb;i++) T[++len] = B[i];
    lenB = Calc(len);

    // S 在 AB 中出现的次数
    len = 0;
    for(int i=1;i<=la;i++) T[++len] = A[i];
    for(int i=1;i<=lb;i++) T[++len] = B[i];
    lenAB = Calc(len)-lenA-lenB;

    // S 在 BA 中出现的次数
    len = 0;
    for(int i=1;i<=lb;i++) T[++len] = B[i];
    for(int i=1;i<=la;i++) T[++len] = A[i];
    lenBA = Calc(len)-lenA-lenB;

    // S 在 BB 中出现的次数
    len = 0;
    for(int i=1;i<=lb;i++) T[++len] = B[i];
    for(int i=1;i<=lb;i++) T[++len] = B[i];
    lenBB = Calc(len)-lenB-lenB;

    // 生成 A 矩阵
    MatrixA.n = MatrixA.m = 12;
    MatrixA.matrix[0][5] = 1;
    MatrixA.matrix[1][6] = 1;
    MatrixA.matrix[2][7] = 1;
    MatrixA.matrix[3][8] = 1;
    MatrixA.matrix[4][9] = 1;
    MatrixA.matrix[5][0] = MatrixA.matrix[5][5] = 1;
    MatrixA.matrix[6][1] = MatrixA.matrix[6][6] = 1;
    MatrixA.matrix[7][2] = MatrixA.matrix[7][7] = 1;
    MatrixA.matrix[8][3] = MatrixA.matrix[8][8] = MatrixA.matrix[8][10] = 1;
    MatrixA.matrix[9][4] = MatrixA.matrix[9][9] = MatrixA.matrix[9][11] = 1;
    MatrixA.matrix[10][11] = MatrixA.matrix[11][10] = 1;


    Matrix f = fsp(MatrixA, n);

    res = (1LL*lenA*f.matrix[0][0]+1LL*lenB*f.matrix[1][0]+1LL*lenAB*f.matrix[2][0]+1LL*lenBA*f.matrix[3][0]+1LL*lenBB*f.matrix[4][0])%MOD;
    cout << res << endl;

    return 0;
}

你可能感兴趣的:(题解)