zoukankan      html  css  js  c++  java
  • [Codeforces955D] Scissors

    给定两个串 (s,t) 整数 (k) ,你可以在 (s) 中取出任意的两个不相交的长度为 (k) 串,将它们按顺序拼在一起形成一个新串。

    求一种取串的方案使得 (t) 是新串的子串。

    (|s|,|t| leq 5 imes 10^5)

    kmp 算出正串和反串的能匹配 (t) 的前/后缀最大长度。

    (s) 串的前缀 ([pre_1 dots pre_i]) 能匹配 (t) 的前缀集合为 (P),后缀 ([suf_{i+1},suf_n]) 能匹配 (t) 的后缀集合为 (Q),只要判断是否存在 (xin P,yin Q,x, yleq k,x+y=|s|) 即可。

    类似 AC 自动机那样建出 fail 树,那么一个点能匹配的前缀长度集合就是在 fail 树上到根的路径,在正串 fail 树上维护集合 (P),每次添加一个数 (x) 时,标记 (k-x) 对应在反串 fail 树上的点,每次查询反串 fail 树上一个点的祖先是否被标记。

    具体实现时,标记一个点可以用子树加一,查询的时候单点查询即可。

    复杂度 (O(n log n))

    #include <bits/stdc++.h>
    #define dbg(...) std::cerr << "33[32;1m", fprintf(stderr, __VA_ARGS__), std::cerr << "33[0m"
    template <class T, class U>
    inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
    template <class T, class U>
    inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
    using LL = long long;
    using PII = std::pair<int, int>;
    
    constexpr int N(1e6 + 5);
    
    int n, m, k;
    std::vector<int> g[N];
    int in[N], out[N], cnt;
    void dfs(int x) {
      in[x] = ++cnt;
      for (int y : g[x]) {
        dfs(y);
      }
      out[x] = cnt;
    }
    int c[N];
    void add(int p, int x) {
      for (; p <= cnt; p += p & -p) {
        c[p] += x;
      }
    }
    int ask(int p) {
      int r = 0;
      for (; p; p -= p & -p) {
        r += c[p];
      }
      return r;
    }
    int main() {
      std::ios::sync_with_stdio(false);
      std::cin.tie(nullptr);
      std::string s, t;
      std::cin >> n >> m >> k >> s >> t;
      std::vector<int> p(m), q(m + n + 1); 
      p[0] = -1;
      for (int i = 1, j; i < m; i++) {
        for (j = p[i - 1]; j >= 0 && t[j + 1] != t[i]; j = p[j]) ;
        p[i] = j + (t[j + 1] == t[i]);
      }
      q[m - 1] = m;
      g[m].push_back(m - 1);
      for (int i = m - 2, j; i >= 0; i--) {
        for (j = q[i + 1]; j < m && t[j - 1] != t[i]; j = q[j]) ;
        q[i] = j - (t[j - 1] == t[i]);
        g[q[i]].push_back(i);
      }
      for (int i = n - 1, j = m; i >= 0; i--) {
        for (; j < m && t[j - 1] != s[i]; j = q[j]) ;
        j -= t[j - 1] == s[i];  
        if (j == 0) {
          if (i >= n - k && k - 1 < n - k) {
            std::cout << "Yes
    " << 1 << " " << n - k + 1 << "
    ";
            return 0;
          }
          j = q[j];
        }
        g[j].push_back(i + m + 1);
        q[i + m + 1] = j;
      }
      dfs(m);
      std::vector<int> vis(m);
      for (int i = 0, j = -1; i < n - k; i++) {
        for (; j >= 0 && t[j + 1] != s[i]; j = p[j]) ;
        j += t[j + 1] == s[i];
        if (j == m - 1) {
          if (i < k && k - 1 < n - k) {
            std::cout << "Yes
    " << 1 << " " << n - k + 1 << "
    ";
            return 0;
          }
          j = p[j];
        }
        if (i < k - 1) continue;
        for (int k = j; k >= m - ::k - 1 && vis[k] <= 0; k = p[k]) {
          vis[k] = i + 1;
          if (k < ::k) {
            add(in[k + 1], 1), add(out[k + 1] + 1, -1);
          } else {
            vis[k] = -vis[k];
          }
        }
        if (ask(in[i + m + 2])) {
          std::cout << "Yes
    ";
          int x = q[i + m + 2];
          for (; x < m && vis[x - 1] <= 0; x = q[x]) ;
          std::cout << vis[x - 1] - k + 1 << " " << i + 2 << "
    ";
          return 0;
        }
      }
      std::cout << "No
    ";
      return 0;
    }
    
  • 相关阅读:
    翻译《Writing Idiomatic Python》(三):变量、字符串、列表
    Jetson TK1刷机+配置Mini PCI-e无线网卡
    翻译《Writing Idiomatic Python》(二):函数、异常
    翻译《Writing Idiomatic Python》(一):if语句、for循环
    用Python和摄像头制作简单的延时摄影
    安卓加固之so文件加固
    Windbg+VirtualBox双机调试环境配置(XP/Win7/Win10)
    Sizeof Class
    32位和64位系统内核函数调用从ZwProtectVirtualMemory到NtProtectVirtualMemory
    JNI注册调用完整过程-安卓4.4
  • 原文地址:https://www.cnblogs.com/HolyK/p/14238236.html
Copyright © 2011-2022 走看看