1 条题解

  • 0
    @ 2025-8-24 22:11:12

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ccxswl
    傻不拉几的

    搬运于2025-08-24 22:11:12,当前版本为作者最后更新于2024-08-18 12:09:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    洛谷题面。

    模拟赛出到加强版了,一点不会所以记录下。


    枚举每个后缀。设 fi,jf_{i,j} 为操作 ii 次,长度增加 jj,即插入的次数减删除的次数,所能匹配到的最大位置。也就是 AA 的前 fi,jf_{i,j} 位匹配 BB 的前 fi,j+jf_{i,j}+j 位。

    考虑转移。假如已经操作完了,那显然有 $f_{i,j} \gets f_{i,j}+\text{LCP}(A[f_{i,j}+1:|A|],B[f_{i,j}+j+1:|B|])$。

    进行操作的转移:

    • 替换:fi+1,jfi,j+1f_{i+1,j} \gets f_{i,j}+1
    • 删除:fi+1,j1fi,j+1f_{i+1,j-1} \gets f_{i,j}+1
    • 添加:fi+1,j+1fi,jf_{i+1,j+1}\gets f_{i,j}

    一些解释:添加操作的时候,AA 多了一个虚拟的点,但最后一个匹配到的真正存在的点还是 fi,jf_{i,j}。删除操作的时候,那个被删的点也看做完成了匹配。

    转移时注意多判边界。

    LCP 可以直接用二分哈希,其实 SA 可以更快,但二分哈希完全够用。

    最后统计答案记得找到最小操作次数后要跳出循环。

    复杂度 O(nk2logn)O(nk^2\log n)。如果用 SA 的话是 O(nk2)O(nk^2)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define int long long
    
    using ubt = unsigned long long;
    
    const int maxN = 1e5 + 7;
    
    int k;
    int n, m;
    string s, t;
    
    const ubt Base = 131;
    ubt H[maxN], S[maxN], T[maxN];
    void inithash() {
      H[0] = 1, S[0] = T[0] = 0;
      for (int i = 1; i <= n || i <= m; i++) {
        if (i <= n) S[i] = S[i - 1] * Base + s[i];
        if (i <= m) T[i] = T[i - 1] * Base + t[i];
        H[i] = H[i - 1] * Base;
      }
    }
    ubt gets(int l, int r) {
      return S[r] - S[l - 1] * H[r - l + 1];
    }
    ubt gett(int l, int r) {
      return T[r] - T[l - 1] * H[r - l + 1];
    }
    
    int LCP(int ss, int st) {
      int l = 1, r = min(n - ss + 1, m - st + 1);
      int pos = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (gets(ss, ss + mid - 1) == gett(st, st + mid - 1))
          l = mid + 1, pos = mid;
        else r = mid - 1;
      }
      return pos;
    }
    
    const int inf = 1e9;
    const int V = 7;
    int ans[V];
    int st;
    int f[V][V * 2];
    void Main() {
      memset(f, ~0x3f, sizeof(f));
      f[0][k] = 0;
      for (int i = 0; i <= k; i++)
        for (int j = 0; j <= k * 2; j++) {
          if (f[i][j] <= -inf) continue;
          int p = j - k;
          if (f[i][j] + p < 0) continue;
          if (st - 1 + f[i][j] + p > m) continue;
          f[i][j] += LCP(f[i][j] + 1, st - 1 + f[i][j] + p + 1);
          if (i != k) {
            if (j)
              f[i + 1][j - 1] = max(f[i + 1][j - 1], min(f[i][j] + 1, n));
            f[i + 1][j] = max(f[i + 1][j], min(f[i][j] + 1, n));
            if (j != k * 2)
              f[i + 1][j + 1] = max(f[i + 1][j + 1], f[i][j]);
          }
        }
    
      for (int i = 0; i <= k * 2; i++)
        for (int j = 0; j <= k; j++)
          if (f[j][i] == n && i - k + n > 0 && st - 1 + i - k + n <= m)
          { ans[j]++; break; }
    }
    
    signed main() {
      // ifstream cin("edit.in");
      // ofstream cout("edit.out");
    
      cin >> k >> s >> t;
      n = s.length(), m = t.length();
      s = '@' + s, t = '$' + t;
    
      inithash();
    
      for (st = 1; st <= m; st++)
        Main();
      
      int res = 0;
      for (int i = 0; i <= k; i++)
        res += ans[i];
      cout << res << '\n';
    }
    

    更新:代码有点问题,修了。

    • 1

    信息

    ID
    4474
    时间
    2000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者