1. 程式人生 > >Problem 4. Stringonomics 2018 Goldman Sachs Women's CodeSprint

Problem 4. Stringonomics 2018 Goldman Sachs Women's CodeSprint

題意:輸入字串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;
}