• 1009: [HNOI2008]GT考试


    1009: [HNOI2008]GT考试

    https://www.lydsy.com/JudgeOnline/problem.php?id=1009

    分析:

      f[i][j]表示第一个字符串到i,与第二个匹配了j个的方案数。新加一个字符,如果第一个字符串仍与第二个一样,那么转移到f[i+1][j+1],否则,转移到f[i+1[k],k是不确定的。预处理g[i][j]表示两个字符串匹配了i,然后增加一个字符后,匹配的位数变成j后的方案数。

      那么有转移方程:$dp[i][j]=sum_{0<=k<=m-1}dp[i-1][k] imes g[k][j]$

      然后发现n特别大,但是每个i转移只有20-1(等于m了,就不用记录了)个,所以可以矩阵快速幂。

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<cctype>
     7 #include<set>
     8 #include<vector>
     9 #include<queue>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13 
    14 inline int read() {
    15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    17 }
    18 
    19 const int N = 100;
    20 
    21 int p[N], g[N][N];
    22 char s[N];
    23 int n, m, mod;
    24 
    25 struct Matrix{
    26     int a[N][N];
    27     void init() {
    28         for (int i=0; i<m; ++i) a[i][i] = 1;
    29     }
    30     void Clear() {
    31         memset(a, 0, sizeof(a));
    32     }
    33 }A;
    34 Matrix mul(Matrix A, Matrix B) {
    35     Matrix C; C.Clear();
    36     for (int k=0; k<m; ++k) 
    37         for (int i=0; i<m; ++i)
    38             for (int j=0; j<m; ++j) 
    39                 C.a[i][j] = (C.a[i][j] + 1ll * A.a[i][k] * B.a[k][j] % mod) % mod;
    40     return C;
    41 }
    42 Matrix ksm(Matrix a,int b) {
    43     Matrix res; res.Clear(); res.init();
    44     while (b) {
    45         if (b & 1) res = mul(res, a);
    46         a = mul(a, a);
    47         b >>= 1;
    48     }
    49     return res;
    50 }
    51 void KMP() {
    52     p[1] = 0;
    53     for (int i=2; i<=m; ++i) {
    54         int j = p[i - 1];
    55         while (j && s[j + 1] != s[i]) j = p[j];
    56         if (s[j + 1] == s[i]) j ++;
    57         p[i] = j;
    58     }
    59     for (int i=0; i<=m; ++i) {
    60         for (int j='0'; j<='9'; ++j) {
    61             int k = i;
    62             while (k && s[k + 1] != j) k = p[k];
    63             if (s[k + 1] == j) g[i][k + 1] ++;
    64             else g[i][0] ++;
    65         }
    66     }
    67 }
    68 int main() {
    69     n = read(), m = read(), mod = read();
    70     scanf("%s",s+1);
    71     KMP();
    72     for (int i=0; i<=m; ++i) 
    73         for (int j=0; j<=m; ++j) 
    74             A.a[i][j] = g[i][j];
    75     A = ksm(A, n);
    76     int Ans = 0;
    77     for (int i=0; i<m; ++i) 
    78         Ans = (Ans + A.a[0][i]) % mod;
    79     cout << Ans;
    80     return 0;
    81 }
  • 相关阅读:
    "INVALID" is not a valid start token
    Win+R 快速启动程序
    assert False 与 try 结合 在开发中的使用
    token的分层图如下
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError
    获取控制台的错误信息 onerror
    状态git
    icmp
    git commit前检测husky与pre-commit 提交钩子
    git diff
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9643291.html
Copyright © 2020-2023  润新知