Cod sursa(job #1258866)

Utilizator gabrieligabrieli gabrieli Data 9 noiembrie 2014 15:17:15
Problema Potrivirea sirurilor Scor 16
Compilator cpp Status done
Runda Arhiva educationala Marime 2.38 kb
#include <cmath>
#include <cstdint>
#include <fstream>
#include <string>
#include <utility>
#include <vector>
using namespace std;

constexpr uint64_t S1 = 1.140071482E19,
                   S2 = 7.600476546E18;
constexpr uint64_t BASE = 128;

inline uint64_t hash(const uint64_t key, const uint64_t s) {
    return key * s;
}

uint64_t prehash(const string& s, const uint64_t base) {
    uint64_t value = 0;
    for (char c : s)
        value = value * base + c;
    return value;
}

class RollingPreHash {
    string text;
    uint64_t ph_value;
    uint64_t ph_base, ph_base_pow_length;
    size_t ph_length, pos;

public:
    RollingPreHash(
            const string& text,
            const uint64_t base,
            const uint64_t prehash_length) : text(text), ph_base(base), 
                                             ph_length(prehash_length),
                                             ph_value(0), pos(0) {
        if (pos + ph_length <= text.size()) {
            ph_value = prehash(text.substr(0, ph_length), ph_base);
            ph_base_pow_length = pow(ph_base, ph_length);
        }
    }
    
    bool has_next() const { return pos + ph_length <= text.size(); }
    
    pair<uint64_t, size_t> next() {
        uint64_t result = ph_value;
        size_t position = pos;
        
        if (pos + ph_length < text.size()) {
            ph_value = ph_value * ph_base - text[pos] * ph_base_pow_length + text[pos + ph_length];
            pos += 1;
        }
        else if (pos + ph_length == text.size())
            pos += 1;
        
        return make_pair(result, position);
    }
};

int main() {
    ifstream fin("strmatch.in");
    ofstream fout("strmatch.out");
    
    string query, text;
    fin >> query >> text;
    
    const uint64_t HQ1 = ::hash(prehash(query, BASE), S1);
    const uint64_t HQ2 = ::hash(prehash(query, BASE), S2);
    
    size_t matches = 0;
    vector<size_t> positions;
    
    RollingPreHash rph(text, BASE, query.size());
    while (rph.has_next()) {
        pair<uint64_t, size_t> t = rph.next();
        uint64_t& ph = t.first;
        size_t& pos = t.second;
        
        if (::hash(ph, S1) == HQ1 && ::hash(ph, S2) == HQ2) {
            matches++;
            if (matches <= 1000)
                positions.push_back(pos);
        }
    }
    
    fout << matches << '\n';
    for (size_t p : positions) fout << p << ' ';
    fout << endl;
    
    return 0;
}