Cod sursa(job #883422)

Utilizator freak93Adrian Budau freak93 Data 20 februarie 2013 00:20:16
Problema Substr Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.01 kb
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <map>

using namespace std;

class SuffixAutomaton {
  public:
    class element {
      public:
        element(const int &_length = 0, const int &_link = -1, const int &_endings = 0) {
            length = _length;
            link = _link;
            endings = _endings;
            solved = false;
        }

        int length;
        int link;
        int endings;
        map<char, int> edges;
        bool solved;
    };

    SuffixAutomaton(const string &S = "") {
        nodes.push_back(element());
        lastNode = 0;
        for (string::const_iterator c = S.begin(); c != S.end(); ++c)
            extend(*c);
    }

    int getLongestKTimes(const int &K) {
        for (int i = lastNode; i != -1; i = nodes[i].link)
            nodes[i].endings = 1;
        
        getAnswer(0);

        int best = 0;
        for (vector<element>::iterator it = nodes.begin(); it != nodes.end(); ++it)
            if (it -> endings >= K)
                best = max(best, it -> length);

        //for (int i = 0; i < int(nodes.size()); ++i) {
        //    cerr << i << " -> length(" << nodes[i].length << ") link(" << nodes[i].link << ") endings(" << nodes[i].endings << ") edges -> ";
        //    for (map<char, int>::iterator it = nodes[i].edges.begin(); it != nodes[i].edges.end(); ++it)
        //        cerr << "(" << it -> first << " -> " << it -> second << ") ";
        //    cerr << "\n";
        //}
        return best;
    }

  private:
    void extend(char c) {
        int now = nodes.size();
        nodes.push_back(element(nodes[lastNode].length + 1));

        int k;
        for (k = lastNode; k != -1 && !nodes[k].edges.count(c); k = nodes[k].link)
            nodes[k].edges[c] = now;

        lastNode = now;

        if (k == -1) {
            nodes[now].link = 0;
            return;
        }

        int next = nodes[k].edges[c];
        if (nodes[k].length + 1 == nodes[next].length) {
            nodes[now].link = next;
            return;
        }

        // we don't have a possible link, so we clone the node that should follow k
        int clone = nodes.size();
        nodes.push_back(element(nodes[k].length + 1, nodes[next].link));
        nodes[clone].edges = nodes[next].edges;
        for (; k != -1 && nodes[k].edges[c] == next; k = nodes[k].link)
            nodes[k].edges[c] = clone;
        nodes[next].link = nodes[now].link = clone;
    }

    int getAnswer(int nod) {
        if (nodes[nod].solved)
            return nodes[nod].endings;
        for (map<char, int>::iterator it = nodes[nod].edges.begin(); it != nodes[nod].edges.end(); ++it)
            nodes[nod].endings += getAnswer(it -> second);
        nodes[nod].solved = true;
        return nodes[nod].endings;
    }

    vector<element> nodes;
    int lastNode;
};

int main() {
    ifstream cin("substr.in");
    ofstream cout("substr.out");

    int N, K; cin >> N >> K;
    string S; cin >> S;
    
    SuffixAutomaton T(S);

    cout << T.getLongestKTimes(K) << "\n";
}