Cod sursa(job #1571165)

Utilizator alexandru92alexandru alexandru92 Data 17 ianuarie 2016 13:31:31
Problema Potrivirea sirurilor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.83 kb
#include <fstream>
#include <array>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <limits>

using std::string;
using std::vector;
using std::pair;
using std::array;

const int NMAX = 2000011;
const int NUM_OF_MAX_MATCHES_TO_SHOW = 1000;

using BadCharTable = array<vector<int>, std::numeric_limits<char>::max()>;

vector<int> buildSuffixTable(const string& P) {
    vector<int> Z;
    const string rP (P.rbegin(), P.rend());

    Z.resize(P.size());

    Z[0] = rP.size();
    for (int k = 1, lt  = 0, rt = 0; k < rP.size(); ++k) {
        if (k > rt) {
            int i;
            for (i = 0; i + k < rP.size() && rP[i] == rP[i + k]; ++i);
            Z[k] = i;
 
            if (i) {
                lt = k;
                rt = i + k - 1;
            }
        }
        else {
            if (Z[k - lt] < rt - k + 1) {
                Z[k] = Z[k - lt];
            }
            else {
                int i;
                for (i = rt + 1; i < rP.size() && rP[i] == rP[i - k]; ++i);
                Z[k] = i - k;
                lt = k;
                rt = i - 1;
            }
        }
    }

    std::reverse(Z.begin(), Z.end());
    return Z;
}

BadCharTable buildBadCharTable(const string& P) {
    BadCharTable t;

    for (size_t i = 0; i < P.size(); ++i) {
        t[P[i]].push_back(i);
    }

    return t;
}

int computeBadCharShift(const pair<char, int>& x, const BadCharTable& t) {
    const auto& v = t[x.first];
    if (v.empty()) {
        return x.second;
    }
    else if (v.size() <= 15) {
        for (int i = v.size() - 1; i >= 0; --i) {
            if (v[i] < x.second) {
                return x.second - v[i];
            }
        }
        return x.second;
    }
    else {
        auto it = std::lower_bound(v.begin(), v.end(), x.second);
        return x.second - (it == v.begin() ? 0 : *(it - 1));
    }
}

pair<int, vector<int>> strMatch(const string& P, const  string& T) {
    if (P.size() > T.size()) {
       return std::make_pair(0, vector<int>{});
    }
    else if (P.size() == T.size()) {
       return P != T ? std::make_pair(0, vector<int>{}) : std::make_pair(1, vector<int>{0});
    }

    vector<int> L, l;
    vector<int> N = buildSuffixTable(P);
    BadCharTable badCharTable = buildBadCharTable(P);

    L.resize(P.size() + 2);
    l.resize(P.size() + 2);
    for (size_t i = 0; i < P.size() - 1; ++i) {
        int j = P.size() - N[i];
        if (j < P.size()) {
            L[j] = i + 1;
        }
    }

    for (size_t i = 0; i < P.size(); ++i) {
        if (N[i] == i+1) {
            l[P.size() - i - 1] = i + 1;
        }
    }

    for (int i = P.size() - 2; i >= 0; --i) {
        if (0 == l[i]) {
            l[i] = l[i + 1];
        }
    }

    int numMatches = 0, skip = 0;
    vector<int> matches;

    matches.reserve(NUM_OF_MAX_MATCHES_TO_SHOW);
    for (size_t i = P.size() - 1; i < T.size(); i += skip) {
        int k = i, j = P.size() - 1;
        for (; j >= 0 && T[k] == P[j]; --k, --j);

        if (j < 0) {
            skip = P.size() - l[1];
            ++numMatches;
            if (numMatches <= matches.capacity()) {
                matches.push_back(k + 1);
            }
        }
        else {
            skip = std::max(1, computeBadCharShift({T[i], j}, badCharTable));
            if (j == P.size() - 1) {
            }
            else if (L[j + 1] > 0) {
                skip = std::max<int>(skip, P.size() - L[j + 1]);
            }
            else {
                skip = std::max<int>(skip, P.size() - l[j + 1]);
            }
        }
    }

    return std::make_pair(numMatches, matches);
}


int main() {
    string P, T;
    std::ifstream in{"strmatch.in"};
    std::ofstream out{"strmatch.out"};

    in >> P >> T;
    const auto x = strMatch(P, T);
    out << x.first << '\n';
    std::copy(x.second.begin(), x.second.end(), std::ostream_iterator<int>{out, " "});

    return 0;
}