Mamy dwa słowa
Najpierw rozważmy trochę prostszy problem słów „cyklicznie równoważnych”.
Wtedy istnieje podział
i s_1: ....UUUU|VVV.... j s_2: ..VVV|UUUU......
Teraz osobno rozważymy każdą długość
Złożoność będzie wynosić
Na koniec powróćmy do problemu „równoważności naszyjnikowej”.
Tu przyda nam się techniczna sztuczka: wystarczy jeszcze raz wykonać algorytm
równoważności cyklicznej dla słowa
Kod wygląda następująco i zalicza dwa podzadania:
const int N = 3100; char s1[N],s2[N]; int n1,n2; int lcp[N][N]; int ans=0, ai, aj; void solve(bool rev) { for(int i=n1-1; i>=0; --i) { for(int j=n2-1; j>=0; --j) { if (s1[i] == s2[j]) { lcp[i][j] = 1 + lcp[i+1][j+1]; } else { lcp[i][j] = 0; } } } REP(i,n1+1) REP(j,n2+1) { int len_a=0, len_b=0; REP(len,i+1) { if (lcp[i-len][j] >= len) { len_a = len; } } REP(len,j+1) { if (lcp[i][j-len] >= len) { len_b = len; } } if (len_a + len_b > ans) { ans = len_a + len_b; ai = i-len_a; aj = rev ? n2-j-len_a : j-len_b; } } } int main() { scanf("%s%s",s1,s2); n1 = strlen(s1); n2 = strlen(s2); solve(false); reverse(s2,s2+n2); solve(true); printf("%d\n%d %d\n", ans, ai, aj); }
Spróbujemy szybciej wyznaczać wartości
Możemy zatem przejść po wszystkich takich fragmentach i utrzymywać
najdłuższy „daszek”, który ciągle pokrywa naszą pozycję
REP(i,n1+1) { int idx = -1; REP(j,n2+1) { while (idx == -1 || idx < j && idx + lcp[i][idx] <= j) { idx++; } int len = 0; if (idx + lcp[i][idx] > j) { len = j - idx + 1; } cache_len_b[i][j+1] = len; } } REP(j,n2+1) { int idx = -1; REP(i,n1+1) { while (idx == -1 || idx < i && idx + lcp[idx][j] <= i) { idx++; } int len = 0; if (idx + lcp[idx][j] > i) { len = i - idx + 1; } cache_len_a[i+1][j] = len; } }
Analogicznie wyznaczamy tablicę
Poprzednie rozwiązanie wymaga pamięci
Odpowiadanie na zapytania o
Iterujemy się po wszystkich wartościach
Po przeorganizowaniu kodu liczącego tablicę
Dzięki temu odzyskamy odpowiedź dla ustalonej pozycji