zoukankan      html  css  js  c++  java
  • [HNOI2008]GT考试

    题意

    有一个长度为(n)((nle1e^9))只由阿拉伯数字组成的串(A),现在给一个长度为(m)((mle20))同样只由阿拉伯数字组成的串(B),求满足条件的(A)串个数,条件:(B)串不包含在(A)串。

    题解

    (dp[i][j]=)长度为(i)且末尾(后缀)已经与(B)串首部(前缀)匹配了(j)位的满足条件的串的方案数。则:$$dp[i][j] = sum_{k = 0}^{m - 1}dp[i - 1][k]a[k][j]$$ (a[k][j]=) 已经匹配了(k)位现在再加一个数字而能匹配(j)位的方案数。比如(B)串为(12315)(a[1][1] = 1)就是(1 + ?)能与(12315)匹配(1)位的方案数是1的(?)的取值个数((? = 1))。这里讲的匹配是指(1?)的后缀与(12315)的前缀相同的串的长度。$$a =
    egin{pmatrix}
    9 & 1 & 0 & 0 & 0 & 0
    8 & 1 & 1 & 0 & 0 & 0
    8 & 1 & 0 & 1 & 0 & 0
    9 & 0 & 0 & 0 & 1 & 0
    7 & 1 & 1 & 0 & 0 & 1
    end{pmatrix}$$行代表(k),列代表(j)。如何求出(a)数组?既然是在求公共的前缀和后缀,故联想到(KMP)(Next)数组。具体做法见代码。观察上面的转移方程,系数都是常数且是一次方程,自然而然的转化为矩阵的乘积形式,(m) = 5,(B)串为:12315为例$$egin{pmatrix}
    dp[i][0] & dots & dp[i][m - 1]
    end{pmatrix}=
    egin{pmatrix}
    dp[i - 1][0] & dots & dp[i - 1][m - 1]
    end{pmatrix}

    egin{pmatrix}
    9 & 1 & 0 & 0 & 0
    8 & 1 & 1 & 0 & 0
    8 & 1 & 0 & 1 & 0
    9 & 0 & 0 & 0 & 1
    7 & 1 & 1 & 0 & 0
    end{pmatrix}$$因为是求不包含(B)串的A串个数,故(a)矩阵的最后一列应该忽略。

    const int N = 100005;
     
    int mod;
     
    struct mat {
        int t;
        int A[22][22];
        mat() {
            mem(A, 0);
        }
        void Inite(int m) {
            t = m;
        }
        mat operator * (const mat& tp) {
            mat ans;
            ans.t = tp.t;
            rep(i, 0, t) rep(j, 0, t) rep(k, 0, t) {
                ans.A[i][j] += A[i][k] * tp.A[k][j];
                ans.A[i][j] %= mod;
            }
            return ans;
        }
        void operator = (const mat& tp) {
            t = tp.t;
            rep(i, 0, t) rep(j, 0, t) A[i][j] = tp.A[i][j];
        }
    };
     
    int n, m;
    int nxt[22];
     
    string s;
     
    mat qpow(mat C, int x) {
        mat B;
        B.Inite(m);
        rep(i, 0, m) B.A[i][i] = 1;
        for (; x; C = C * C, x >>= 1) if (x & 1) B = B * C;
        return B;
    }
     
    void Next(){
        nxt[0] = nxt[1] = 0;
        rep(i, 1, m) {
            int k = nxt[i];
            while(k && s[k] != s[i]) k = nxt[k];
            nxt[i + 1] = (s[k] == s[i] ? k + 1 : 0);
        }
    }
     
    int main()
    {
        cin >> n >> m >> mod >> s;
     
        Next();
     
        mat B;
        B.Inite(m);
     
        rep(i, 0, m) for (char j = '0'; j <= '9'; ++j) {
            int k = i;
            while(k && s[k] != j) k = nxt[k];
            if (s[k] == j) k++;
            if (k != m) B.A[i][k]++;
        }
     
        mat C = qpow(B, n);
     
        mat D;
        D.Inite(m);
        D.A[0][0] = 1;
     
        C = D * C;
     
        int ans = 0;
        rep(i, 0, m) ans = (ans + C.A[0][i]) % mod;
        cout << ans << endl;
     
     
        return 0;
    }
    
    
  • 相关阅读:
    poj-3580-SuperMemo-splay
    JS 添加到事件的多个对象
    1.9 效率高,安排约会
    我展示了视频采集前端vfe和camera,decode等交互驱动的体系结构
    2013年7月27日杂记
    深入JS系列学习4
    深入JS系列学习3
    深入JS系列学习2
    高质量JavaScript代码书写基本要点学习
    给硬件复兴把脉 硬件创新最有机会的十个方向
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9729284.html
Copyright © 2011-2022 走看看