Educational Codeforces Round 178 (Rated for Div. 2) E. Unpleasant Strings
题意
给定一个字符串\(s\)和若干字符串\(a_i\) , 求\(a_i\)加上多少个字符后不再是\(s\)的一部分
思路
如何快速判断一个字符串是否为另一个字符串的子串 ? (此处指可以任意删去某些字符 , 而不是连续子串)
朴素的方法是双指针 , 贪心匹配 ; 另一种很经典的方法是通过设定\(lst\)数组 , 记录每个字符最后出现的位置 , 从而倒序得到一个跳转数组
设子串长度为\(t\) , 那么就可以在\(O(t)\)的时间内得到最大匹配的位置
设定好之后就可以找到给定子串的最大匹配处
然后考虑到达\(pos\)后 , 需要多少个字符才能使其满足题意
此时的\(pos\)和子串本身是什么已经无关了 , 所以是一个固定值
所以用dp倒序求解即可
代码
#include<bits/stdc++.h>
using namespace std;
#define debug false
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
const int N = 1e6+10;
int af[N][30];
int dp[N];
int lst[30];
string s;
int n,k;
void solve() {
string tmp;
cin>>tmp;
int pos=0;
for (int i = 0; i < tmp.size(); i++) {
int c = tmp[i]-'a'+ 1;
pos = af[pos][c];
}
cout<<dp[pos]<<"\n";
}
int main() {
memset(dp,0x3f,sizeof dp);
n =read(),k=read();
for (int i =1 ;i<= k; i++) {
lst[i] = n+1;
}
cin>>s;
s= " " + s;
dp[n+1] = 0;
for (int i = 1; i<= k; i++) {
af[n+1][i] = n+1;
}
for (int i = n; i>=0; i--) {
for (int j = 1; j<= k; j++) {
af[i][j] = lst[j];
dp[i] = min(dp[i],dp[lst[j]] + 1);
}
if (i!=0)
lst[s[i]-'a'+1] = i;
}
int q=read();
while (q--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号