• Codeforces 808G Anthem of Berland【KMP】【DP】


    LINK


    简要题意

    给你一个串s,上面有字母和一些通配符,问你将通配符换成字母之后最多可以出现多少次串t


    首先有一个很傻子的做法就是(dp_{i,j})表示s到第i个位置匹配t串前j个字符的完整t串个数
    然后每次枚举前缀看看能不能转移。。。太不优秀了

    那么就考虑这样做:
    (dp_{i})表示最后一个出现的完整的串t在第i个位置结尾的最大出现次数
    (maxv_{i})表示最后一个出现的完整的串t在第i个位置前结尾的最大出现次数

    首先有一个转移是,如果当前位置被匹配,那么(dp_{i} = maxv_{i - lent} + 1)
    或者我们就需要枚举当前串和上一个的公共长度
    这样就相当于枚举t的一个是前缀又是后缀的东西
    就很容易想到跳fail

    然后就加上一个kmp板子就可以了

    复杂度是(|s|*|t|)


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1e5 + 10;
    char s[N], t[N];
    int fail[N], dp[N], maxv[N];
    void getfail(char *s) {
      int lens = strlen(s + 1);
      int j = 0; fail[1] = 0;
      fu(i, 2, lens) {
        while (j && s[j + 1] != s[i]) j = fail[j];
        if (s[j + 1] == s[i]) ++j;
        fail[i] = j;
      }
    }
    bool match(char *s, int pos, char *t, int len) {
      fu(i, 1, len)
        if (s[pos + i -1] != t[i] && s[pos + i - 1] != '?') return 0;
      return 1;
    }
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      scanf("%s%s", s + 1, t + 1);
      getfail(t);
      int lens = strlen(s + 1), lent = strlen(t + 1);
      fu(i, lent, lens) {
        if (match(s, i - lent + 1, t, lent)) {
          dp[i] = max(dp[i], maxv[i - lent] + 1); 
          int j = fail[lent];
          while (j) {
            dp[i] = max(dp[i], dp[i - (lent - j)] + 1);
            j = fail[j];
          }
          maxv[i] = max(maxv[i], dp[i]);
        }
        maxv[i] = max(maxv[i], maxv[i - 1]);
      }
      Write(maxv[lens]);
      return 0;
    }
    
  • 相关阅读:
    HDU 2899 Strange fuction
    HDU 2899 Strange fuction
    HDU 2199 Can you solve this equation?
    HDU 2199 Can you solve this equation?
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9769958.html
Copyright © 2020-2023  润新知