Shik and Copying String[agc007F]

Description

​ 有一个长度为\(n\)字符串\(S_0\),定义一次操作i为将\(S_{i-1}\)复制到\(S_i\)中,那么我们记\(S_i[j]\)表示串\(S_i\)中的第\(j\)个字符。另外,由于一些神秘原因,\(S_i[j]=S_i[j - 1]\)或者\(S_{i-1}[j]\)。给出另一个长度为\(n\)字符串\(T\),求出最小的\(i\),满足\(S_i=T\),如果不存在这样的\(T\),输出\(-1\)

Solution

​ 考虑手算,我们画出一条转移

\[a \ b \ c \ d \ e \\ \downarrow \\ \ \ \ \rightarrow \\ \ \ \ \ \ \ \downarrow \\ a \ a \ a \ c \ c \]

​ 这是其中的一条覆盖后两个字符的转移折线,最后的转移应该是由一些覆盖整个\(T\)串的折线组成,答案就是折线的拐点数的最大值,也就是从\(\rightarrow\) 变成 \(\downarrow\)的次数的最大值。

​ 我们对于\(T\)串从后往前扫,设当前扫到了\(i\),找出\(S_0\)串中不超过上一个折线的最左匹配位置\(j:j \leqslant i \ \&\& S_j = T_i\),分类讨论(我们记上一条折线的起点为k):

1、如果\(j=k\),那么我们直接将上一条折线往下移一位,并删除大于\(i\)的拐点。

2、如果\(j \not = k\), 那么我们将上一条折线往下移一位,并往左移一位统计答案并加入当前的拐点

Hint

\(N \leqslant 10^6\),全部都是小写字母

Code

/**************************************************************
    Problem: 3184
    User: ez_hjw
    Language: C++
    Result: Accepted
    Time:56 ms
    Memory:7804 kb
****************************************************************/
 
 
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<deque>
using namespace std;
const int maxn = 1000000 + 10;
 
int n, ans = 0;
char a[maxn], b[maxn];
deque <int> q;
 
int main() {
  scanf("%d", &n);
  scanf("%s%s", a + 1, b + 1);
  q.push_back(n + 1);
  for(int i = n, j = n + 1, del = 0;i >= 1;i --) {
    int tmp = j;
    while(j && (j > i || a[j] != b[i])) j --;
    if(!j) {
      puts("-1");
      return 0;
    }
    if(tmp == j) {
      while(!q.empty() && q.back() - del >= i) q.pop_back();
      q.push_back(i + del);
    }
    else {
      del ++;
      if(i != j) {
        ans = max(ans,(int)q.size());
        q.push_front(j + del);
      }
    }
  }
  printf("%d\n", ans);
  return 0;
}
原文地址:https://www.cnblogs.com/ezhjw/p/9513447.html