zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    黑胶100
    界面滑动+ztree
    Linux下Java获取本机IP地址
    垂直对齐vertical-align:top
    针对jquery获取表单数据并且迭代方式
    js传递参数中文乱码
    前端开发资源库
    webpack加载器(Loaders)
    webpack基础知识点
    webpack操作基础
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9769958.html
Copyright © 2011-2022 走看看