Problem 4. Stringonomics 2018 Goldman Sachs Women's CodeSprint
阿新 • • 發佈:2018-11-09
題意:輸入字串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; }