Cod sursa(job #3300536)

Utilizator stefan05Vasilache Stefan stefan05 Data 16 iunie 2025 22:36:30
Problema Potrivirea sirurilor Scor 34
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.46 kb
#include <fstream>
#include <cstring>

#define SMAX 2000005
#define ALFMAX 26

using namespace std;

ifstream fin("strmatch.in");
ofstream fout("strmatch.out");

char pattern[SMAX];
char s[SMAX];
int bc[ALFMAX], gs[SMAX];
int f[SMAX], h[SMAX];
int rez[SMAX]; int nr;
int k, i;

int main()
{
    fin >> pattern >> s;
    int m = strlen(pattern);
    int n = strlen(s);


    ///PRECALCULARI
    ///bc[i] = ultima aparitie in pattern a caracterului char(i+'a')

    for (i = 0; i < 26; ++i)
        bc[i] = -1;
    for (i = 0; i < m; ++i)
        bc[pattern[i] - 'A'] = i;

    ///gs[i] = ultima aparitie in pattern a sufixului pattern[i..m-1] 

    //f[i] = cel mai mare sufix care e si prefix pentru pattern[0...i-1] (primele i)
    // h[i] = cel mai mare sufix care e si prefix pentru pattern[i...m-1] 
    // cum se afla h: aflam f pentru pattern inversat, inversam asta

    f[0] = h[0] = -1;
    for (i = 1; i <= m; ++i)
    {
        int k;
        k = f[i - 1];
        while (k >= 0 && pattern[k] != pattern[i - 1]) //din kmp
            k = f[k];
        if (k == -1)
            f[i] = 0;
        else
            f[i] = k + 1;

        //indici inversati
        k = h[i - 1];
        while (k >= 0 && pattern[m - 1 - k] != pattern[m - 1 - (i - 1)]) //din kmp
            k = h[k];
        if (k == -1)
            h[i] = 0;
        else
            h[i] = k + 1;
    }
    //inverseaza h
    int st, dr;
    for (st = 0, dr = m; st < dr; ++st, --dr)
        swap(h[st], h[dr]);

    //pentru pozitiile negative
    for (i = 0; i < m; ++i)
        gs[i] = f[m] - (m - i);
    //vrem sufix-prefix de lungime i, avem doar f[m]

//pentru pozitiile pozitive
    for (i = 0; i < m; ++i)
    {
        int lg = h[i];

        //pentru sufixul lui pattern cu lungime lg, care incepe la pozitia m-lg, l-am gasit pe pozitia i
        gs[m - lg] = i;
    }


    ///REZOLVARE

    //k = deplasament = lungimea bucatii corecta din dreapta
    //i = pozitia pentru care testam: "apare pattern la pozitia i?"
    i = 0; k = 0;
    while (i <= n - m) //daca k == m, am gasit pattern
        //daca i == n-m, suntem la sfarsit cu pattern-ul
    {
        if (k == m)
        {
            rez[++nr] = i;
            int shiftbc = m - (k + 1) - bc[s[i + m - 1 - k] - 'A'];
            int shiftgs = max(1, m - k - gs[m - k]);
            i += max(shiftbc, shiftgs);
            k = 0;
        }
        if (s[i + m - 1 - k] == pattern[m - 1 - k])
            k++;
        //al k-lea caracter (caracterul curent) de la dr la st e corect
        else
        {
            //shift = cu cat trebuie sa mutam pattern
            //shift = max(shiftbc, shiftgs), mut maxim posibil fara sa pierd cazuri

            //s[i+m-1-k] este primul caracter gresit
            int shiftbc = m - (k + 1) - bc[s[i + m - 1 - k] - 'A'];
            //m-(k+1) este pozitia fix dinainte de ultimele k elemente, care sunt corecte
            //trebuie sa ajungem de la m-(k+1) la bc[s[i + m - 1 - k]], facem shiftbc pasi

            int shiftgs = max(1, m - k - gs[m - k]);
            
            //la poz m-k incep cele k elemente corecte gasite pana acum
            //trebuie sa ajungem de la m-k la gs[m-k], facem shiftgs pasi

            i += max(shiftbc, shiftgs);
            k = 0;
        }
    }

    fout << nr << '\n';
    for (i = 1; i <= min(nr, 1000); ++i)
        fout << rez[i] << ' ';
    fout << '\n';
    return 0;
}