Cod sursa(job #2123983)

Utilizator Mihai_PredaPreda Mihai Dragos Mihai_Preda Data 6 februarie 2018 19:31:03
Problema Substr Scor 80
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.32 kb
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

struct suffix
{
    int pos;
    pair<int, int> Rank;
    bool operator <(const suffix &that) const
    {
        return Rank < that.Rank;
    }
};

class SuffixArray
{
public:
    vector<vector<int> > Rank;
    vector<int> rankPos;
    SuffixArray(const string &s)
    {
        this->s = s;
        int n = s.size();
        vector<suffix> v(n);
        SetLog();
        Rank.resize(log[n] + 3, vector<int>(n));
        for(int i = 0; i < n; ++i)
            Rank[0][i] = s[i] - 'a', v[i].pos = i;
        int k, length;
        for(k = 1, length = 1; length / 2 < n; ++k, length *= 2)
        {
            for(int i = 0; i < n; ++i)
            {
                v[i].Rank.first = Rank[k-1][v[i].pos];
                v[i].Rank.second = v[i].pos+length < n ? Rank[k-1][v[i].pos+length] : -1;
            }
            sort(v.begin(), v.end());
            int current = 0;
            Rank[k][v[0].pos] = current;
            for(int i = 1; i < n; ++i)
                Rank[k][v[i].pos] = v[i].Rank == v[i-1].Rank ? current : ++current;
        }
        if(length/2 == n)
            Rank.pop_back();
    }
    void PreprocessLcp()
    {
        int n = s.size();
        int x, y, lg = log[n];
        vector<int> LCP(n); //LCP intre i si i+1
        rankPos.resize(n);
        for(int i = 0; i < n; ++i)
            rankPos[Rank.back()[i]] = i;
        for(int i = 0; i < n-1; ++i)
            LCP[i] = GetLogLcp(rankPos[i], rankPos[i+1]);
        rmqLcp.resize(lg, vector<int>(n, n));
        for(int i = 0; i < n; ++i)
            rmqLcp[0][i] = LCP[i];
        for(int i = 1; i < lg; ++i)
            for(int j = 0; j + (1 << (i - 1)) < n; ++j)
                rmqLcp[i][j] = min(rmqLcp[i-1][j], rmqLcp[i-1][j + (1 << (i - 1))]);
    }
    int GetLogLcp(int x, int y)
    {
        if(x > y)
            swap(x, y);
        int n = s.size();
        int ret = 0;
        int lg = log[n];
        for(int step = lg-1; step >= 0 && x < n && y < n; --step)
            if(Rank[step][x] == Rank[step][y])
                ret |= (1 << step), x += (1 << step), y += (1 << step);
        return ret;
    }
    int GetLcp(int x, int y) // 0-indexed
    {
        x = Rank.back()[x];
        y = Rank.back()[y];
        if(x > y)
            swap(x, y);
        y--;

        if(x == y)
            return rmqLcp[0][x];
        int lg = log[y - x + 1];
        if((1 << lg) == y - x + 1)
            lg--;
        return min(rmqLcp[lg][x], rmqLcp[lg][y - (1 << lg) + 1]);
    }
private:
    string s;
    vector<vector<int> > rmqLcp;
    vector<int> log;
    void SetLog()
    {
        log.resize(s.size()+1);
        log[1] = 0;
        for(int i = 2; i < s.size()+1; ++i)
            log[i] = log[i/2] + 1;
    }
};

int main()
{
    int n, k;
    string s;
    ifstream in("substr.in");
    in >> n >> k >> s;
    in.close();

    SuffixArray ar(s);
    ar.PreprocessLcp();

    auto &Rank = ar.Rank.back();

    int rasp = 0;
    for(int i = 0; i+k < n; ++i)
        if(Rank[i] + k - 1 < n)
            rasp = max(rasp, ar.GetLcp(i, ar.rankPos[Rank[i] + k - 1]));

    ofstream out("substr.out");
    out << rasp;
    out.close();
    return 0;
}