题解:P10581 [蓝桥杯 2024 国 A] 重复的串

· · 题解



#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int N = 105, mod = 998244353;

int n, m, len, nxt[N];

string s;

struct S {
    ll a[N][N];
} dis, ans;

S operator * (const S &A, const S &B) {
    S C;
    for (ll i = 0; i <= m; i++) {
        for (ll j = 0; j <= m; j++) {
            ll s = 0;
            for (ll k = 0; k <= m; k++) {
                s = (A.a[i][k] * B.a[k][j] % mod + s) % mod;
            }
            C.a[i][j] = s;
        }
    }
    return C;
} //矩阵乘法 

int id(int x, int y) {
    return y * (len + 1) + x;
}  //赋予一个状态编号 

void D(int x) {
    ans.a[0][0] = 1; //初始只有转移到0匹配了0次才是1 
    for (; x; x /= 2, dis = dis * dis) {
        if (x & 1) {
            ans = ans * dis;
        }
    }
}

int main() {
    cin >> s >> n;
    len = s.size();
    s = " " + s + "*";

    for (int i = 2, j = 0; i <= len; i++) {
        for (; j && s[i] != s[j + 1]; j = nxt[j]) {
        }
        j = nxt[i] = j + (s[i] == s[j + 1]);
    }

    //kmp模板 

    m = 3 * (len + 1);

    //注意这里是len+1因为是从0到len的

    for (int i = 0; i <= len; i++) {    //枚举匹配到的位置 
        for (int e = 0; e <= 2; e++) {  //枚举匹配的次数 
            for (char ch = 'a'; ch <= 'z'; ch++) { //枚举下一个字母 
                int j = i;
                for (; j && ch != s[j + 1]; j = nxt[j]) {
                }               
                j += (ch == s[j + 1]); // 算出下一个状态匹配到的位置 
                if (j == len) {
                    if (e == 2) {
                        continue;
                    }                 //我们需要的是恰好两次故超过的不算 
                    dis.a[id(i, e)][id(j, e + 1)]++;
                } else {
                    dis.a[id(i, e)][id(j, e)]++;
                }
            }
        }
    }

    D(n);
    ll sum = 0; 
    for (int i = 0; i <= len; i++) {
        sum += ans.a[0][i + (2 * (len + 1))];  
        sum %= mod;
    } //统计答案 

    cout << sum % mod;
    return 0;
}