BZOJ1009 - GT考试(矩阵加速+kmp)

题目

阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数字A1A2... Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am。(A1和X1可以为0)

题解

看到题目,很自然地就能想到可以用数位dp来解决。但是这题位数太大,不能直接计算(写题的时候被这个限制卡了qwq)。
对于很大的位数,可以考虑用矩阵加速。只要dp转移式是个一次多项式,就可以矩阵加速。
设dp[i][p]为当前在第i位时,匹配到的不吉利的数字长度为p+1。
预处理一个f[p][d]代表不吉利数字位置p后添加数字d到达的位置,这个可以用kmp预处理。然后套矩阵快速幂即可。

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 50;
const double eps = 1e-5;

int nt[N];
int f[N][N];
char s[N];
int k;

struct Mat {
    int n;
    int arr[N][N];
    Mat(int n, int v) : n(n){
        if(v)
            for(int i = 0; i < n; i++) {
                for(int j = 0; j < n; j++) {
                    arr[i][j] = (i == j);
                }
            }
        else 
            for(int i = 0; i < n; i++) {
                for(int j = 0; j < n; j++) {
                    arr[i][j] = 0;
                }
            }
    }
    Mat operator*(Mat & rhs) {
        Mat tmp(n, 0);
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                for(int kk = 0; kk < n; kk++) {
                    tmp.arr[i][j] += (arr[i][kk] * rhs.arr[kk][j]) % k;
                    tmp.arr[i][j] %= k;
                }
            }
        }
        return tmp;
    }
    Mat(const Mat & rhs) {
        n = rhs.n;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                arr[i][j] = rhs.arr[i][j];
            }
        }
    }
    void print() {
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                cout << arr[i][j] << " ";
            }
            cout << endl;
        }
    }
};

Mat qpow(Mat a, int b) {
    Mat res(a.n, 1);
    while(b) {
        if(b & 1) res = res * a;
        a = a * a;
        b = b >> 1;
    }
    return res;
}


void getnext() {
    int i = 0, j = -1;
    int n = strlen(s);
    nt[i] = j;
    while(s[i]) {
        if(j == -1 || s[i] == s[j]) {
            i++, j++;
            nt[i] = j;
        } else {
            j = nt[j];
        }
    }
    for(int p = 0; p <= n; p++) {
        for(int i = 0; i <= 9; i++) {
            int tar = p;
            if(s[tar] - '0' == i) {
                f[p][i] = tar + 1;
            } else {
                f[p][i] = nt[p] < 0 ? 0 : f[nt[p]][i];
            }
        }
    }
}


int main() {
    IOS;
    int n, m;
    cin >> n >> m >> k;
    cin >> s;
    getnext();
    Mat ans(m, 0);
    for(int p = 0; p < m; p++) {
        for(int d = 0; d <= 9; d++) {
            ans.arr[f[p][d]][p]++;
        }
    }
    ans = qpow(ans, n);
    int res = 0;
    for(int i = 0; i < m; i++) {
        res += ans.arr[i][0];
        res %= k;
    }
    cout << res << endl;
}
posted @ 2020-08-14 15:02  limil  阅读(75)  评论(0编辑  收藏  举报