GDOI2016模拟3.9 暴走的图灵机 矩阵乘法优化暴力

来源:互联网 发布:linux mysql 源码安装 编辑:程序博客网 时间:2024/05/22 10:25

题目大意

给你两个字符串lr,初始时l=0,r=1,然后我们有N轮操作,每轮操作把r变成原来的l加上原来r(即连接上),把l变成原来的r
给一个长度为M01s,问操作完后的l串包含多少个s,答案对p取模。

N109    M104    0<p109

解题思路

我们设Ansll串种包含s串的数量,Ansr表示r串种包含s串的数量。显然每一轮我们可以把新串的Ansl变成 AnsrAnsr变成Ansl+Ansr+TT表示l串和r串拼接处产生的s串的数量,我们只需保留l串的后M1位和r的前M1位,拼起来跑一次KMP就可以了。

可是N很大,我们怎么处理。我们列出lr,当它们的长度都至少是2M2时我们发现lr交接处的字符串是有周期性的(在纸上画画就能发现),并且只有交错出现的两种情况,那么球可以确定T的值了,那么再用矩阵乘法跑一跑,因为矩阵乘法是满足结合律的,就可以把两个转移矩阵合起来做。

总结一下,就是暴力跑到长度大于2M2,再用矩阵乘法快速算出答案。

代码

由于比赛时调程序是时比较紧张,导致代码打的很丑。。。。。。真的很丑!

#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long LL;const int MAXS = 1e4 + 5;struct Matrix {    int arr[5][5];} Mar, Mar2, Ans;char S[MAXS + 1], L[MAXS * 100], R[MAXS * 100], Tmp[MAXS * 5], A[MAXS * 2], B[MAXS * 2], C[MAXS * 2];int N, Mo, Lenl, Lenr, Lens, Ansl, Ansr, P[MAXS];Matrix operator * (Matrix a, Matrix b) {    Matrix c;    memset(c.arr, 0, sizeof c.arr);    for (int i = 1; i <= 3; i ++)        for (int j = 1; j <= 3; j ++)            for (int k = 1; k <= 3; k ++)                 c.arr[i][j] = (LL(c.arr[i][j]) + 1ll * a.arr[i][k] * b.arr[k][j]) % Mo;    return c;}Matrix Power(Matrix x, int y) {    Matrix c;    memset(c.arr, 0, sizeof c.arr);    for (int i = 1; i <= 3; i ++) c.arr[i][i] = 1;    for (; y; y >>= 1, x = x * x)        if (y & 1) c = c * x;    return c;}int GetAns(char *L, char *R) {    int l = strlen(L + 1), r = strlen(R + 1);    int t = min(l, Lens - 1), Cnt = t;    for (int i = l; Cnt; i --, Cnt --) Tmp[Cnt] = L[i];    for (int i = 1; i < Lens && i <= r; i ++) Tmp[++ t] = R[i];    int Lst = 0, Ans = 0;    for (int i = 1; i <= t; i ++) {        while (Lst && S[Lst + 1] != Tmp[i]) Lst = P[Lst];        if (S[Lst + 1] == Tmp[i]) Lst ++;        if (Lst == Lens) {            Ans = (Ans + 1) % Mo;            Lst = P[Lst];        }    }    return Ans;}void GetKmp() {    P[1] = 0;    int Lst = 0;    for (int i = 2; i <= Lens; i ++) {        while (Lst && S[Lst + 1] != S[i]) Lst = P[Lst];        if (S[Lst + 1] == S[i]) Lst ++;        P[i] = Lst;    }}int main() {    scanf("%d%d%d", &N, &Lens, &Mo);    scanf("%s", S + 1);    Lenl = Lenr = 1, L[1] = '0', R[1] = '1';    if (Lens == 1) {        if (S[1] == '1') Ansr = 1; else Ansl = 1;    }    int Cnt = 0;    GetKmp();    while (Lenl < 2 * Lens && Cnt < N) {        Cnt ++;        int Ans = GetAns(L, R);        swap(Lenl, Lenr);        swap(Ansl, Ansr), Ansr = ((Ansl + Ansr) % Mo + Ans) % Mo;        swap(L, R);         for (int i = 1; i <= Lenl; i ++) R[Lenr + i] = L[i];        Lenr = Lenr + Lenl;    }    if (N == Cnt) {        printf("%d", Ansl % Mo);        return 0;    }    N = N - Cnt;    for (int i = 1; i < Lens; i ++) A[i] = L[i];    for (int i = Lenl, Cnt = Lens - 1; Cnt; i --, Cnt --) B[Cnt] = L[i];    for (int i = 1; i < Lens; i ++) C[i] = R[i];    Mar.arr[1][1] = 0, Mar.arr[2][1] = 1, Mar.arr[3][1] = 0;    Mar.arr[1][2] = 1, Mar.arr[2][2] = 1, Mar.arr[3][2] = GetAns(B, C);    Mar.arr[1][3] = 0, Mar.arr[3][3] = 1, Mar.arr[3][3] = 1;    Mar2.arr[1][1] = 0, Mar2.arr[2][1] = 1, Mar2.arr[3][1] = 0;    Mar2.arr[1][2] = 1, Mar2.arr[2][2] = 1, Mar2.arr[3][2] = GetAns(B, A);    Mar2.arr[1][3] = 0, Mar2.arr[3][3] = 1, Mar2.arr[3][3] = 1;    Mar2 = Mar * Mar2;    Ans = Power(Mar2, N / 2);    if (N & 1) Ans = Ans * Mar;    int SS = 0;    SS = 1ll * Ansl * Ans.arr[1][1] % Mo;    SS = (LL(SS) + 1ll * Ansr * Ans.arr[2][1] % Mo) % Mo;    SS = (LL(SS) + Ans.arr[3][1]) % Mo;    printf("%d\n", SS);}
2 0
原创粉丝点击