版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yixin94/article/details/83001532
题意:输入字符串S和P,给定Q个queries,每个query操作将S[x]变成c,c也可能和原先的S[x]相同。保证每个位置x只改变一次,而且P不再是S的子串之后不会再重复出现,问对少个query之后P不会再出现S中。
P是从出现到消失,正解是KMP+二分,二分每个mid处判断P是否是S的子串。但是我用O(QN)加上优化竟然也过了。。
KMP一次比较后可以得出P在S中出现的所有位置(最末端匹配处),每个query可能把原先不等于P的A[i,...,j]变成等于P,也可能把原先等于P的子串A[i,...,j]变成不等于P,或者没有影响。
所以不必在每个query都用KMP重新比较,可以维护一个set appear记录P和S match的位置index(match的终点)。
对于query x,P的长度为len,x影响的A中子串以x,x+1,...,x+len-1结尾的子串,所以可以用二分查找找到appear中在此范围内的index,再逐个移除。
如果移除之后appear为空,再用KMP更新匹配结果。
#include <bits/stdc++.h>
using namespace std;
string ltrim(const string &);
string rtrim(const string &);
vector<string> split(const string &);
set<int>appear;//q appear in p, the last matching index
void generateNext(vector<int> &nextArray, string needle) {
nextArray[0] = -1;
int k=-1, q;
for (q = 1; q < needle.length(); ++q) {
while (k>=0 && needle[k+1]!=needle[q])
k = nextArray[k];
if (needle[k+1] == needle[q])
k++;
nextArray[q] = k;
}
// for (int i = 0; i < needle.length(); ++i) {
// cout << nextArray[i] << endl;
// }
}
int match(string hayStack, string needle, vector<int>& nextArray) {
// cout<<"in match "<<hayStack<<" "<<needle<<endl;
if (hayStack.length() < needle.length()) return 0;
if (hayStack.length() == needle.length()) {
if (hayStack == needle)
{
appear.insert(hayStack.length()-1);
return 1;
}
return 0;
}
int q=-1, i=0;
int cnt=0;
for (i = 0; i < hayStack.length(); ++i) {
while (q>=0 && needle[q+1]!=hayStack[i])
q = nextArray[q];
if (needle[q+1] == hayStack[i])
q++;
if (q == needle.length()-1) {
cnt++;
// cout<<"appear at "<<i<<endl;
appear.insert(i);
q = nextArray[q];
}
}
return cnt;
}
int main()
{
string t_temp;
getline(cin, t_temp);
int t = stoi(ltrim(rtrim(t_temp)));
for (int t_itr = 0; t_itr < t; t_itr++) {
string s;
getline(cin, s);
string p;
getline(cin, p);
string q_temp;
getline(cin, q_temp);
int q = stoi(ltrim(rtrim(q_temp)));
vector<int> nextArray(p.length(),0);
generateNext(nextArray,p);
appear.clear();
int ans=0;
bool flg=false;
int cnt=match(s,p,nextArray);
// cout<<"start"<<endl;
if(cnt==0)
{
flg=true;
// cout<<"Case #"<<ca<<": "<<ans<<endl;
cout<<ans<<endl;
// continue;
}
for (int q_itr = 0; q_itr < q; q_itr++) {
string first_multiple_input_temp;
getline(cin, first_multiple_input_temp);
vector<string> first_multiple_input = split(rtrim(first_multiple_input_temp));
int x = stoi(first_multiple_input[0]);
char c = first_multiple_input[1][0];
char prec=s[x];
s[x]=c;
ans++;
if(flg==true)
{
continue;
}
if(c==prec)
{
continue;
}
else
{
// cout<<"here0"<<endl;
int left=x;
int right=x+p.length()-1;
// cout<<"left "<<left<<" right "<<right<<endl;
set<int>::iterator lower=appear.lower_bound(left);
set<int>::iterator upper=appear.upper_bound(right);
if(lower==appear.end())
{
continue;
}
else
{
appear.erase(lower,upper);
if(appear.size()==0)
{
// cout<<"re cmp afer erase at here1"<<endl;
int cnt=match(s,p,nextArray);
if(cnt==0)
{
flg=true;
// cout<<"Case #"<<ca<<": "<<ans<<endl;
cout<<ans<<endl;
}
}
}
}
}
if(flg==false)
{
// cout<<"Case #"<<ca<<": "<<"-1"<<endl;
cout<<"-1"<<endl;
}
}
return 0;
}
string ltrim(const string &str) {
string s(str);
s.erase(
s.begin(),
find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace)))
);
return s;
}
string rtrim(const string &str) {
string s(str);
s.erase(
find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(),
s.end()
);
return s;
}
vector<string> split(const string &str) {
vector<string> tokens;
string::size_type start = 0;
string::size_type end = 0;
while ((end = str.find(" ", start)) != string::npos) {
tokens.push_back(str.substr(start, end - start));
start = end + 1;
}
tokens.push_back(str.substr(start));
return tokens;
}