Baltic OI 2019 - Necklace

Author: Andi Qu

Solution 1 (Magic DP)

Time complexity: O(N2)\mathcal O(N^2). Memory complexity: O(N)\mathcal O(N).

This section is not complete.

Any help would be appreciated! Just submit a Pull Request on Github.

The editorial describes this approach so awfully :(. "Analyze the recurrences carefully"

Code

//DP: time O(n^2), mem O(n)
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int solve_noflip(string &s, string &t, int *loc) {
int n = s.size(); // vertical

Solution 2 (KMP)

Time complexity: O(N2)\mathcal O(N^2). Memory complexity: O(N)\mathcal O(N).

Let the two strings be SS and TT, and their lengths be NN and MM respectively.

For simplicity, assume that we can't flip the necklace over. (To handle the case where we can, just reverse TT, run our algorithm again, and take the best result.)

We essentially want to find two strings AA and BB, and two indices ii and jj such that:

  • AA is a suffix of S[0:i]S[0 : i] and a prefix of T[j+1:M1]T[j + 1 : M - 1].
  • BB is a prefix of S[i+1:N1]S[i + 1 : N - 1] and a suffix of T[0:j]T[0 : j].
  • A+B|A| + |B| is maximal.

We can thus test each ii to find the best jj for that ii, and then take the best overall result.

To find the best jj, we first reverse TT and split SS at index ii. This turns the subproblem into finding the longest common prefix/suffix between two pairs of strings. This is a classical application of KMP, so we can solve this subproblem in O(N)\mathcal O(N) time and O(N)\mathcal O(N) memory.

Code

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int p1[6002], p2[6002];
void fill_p(string s, int *p) {
for (int i = 1; i < s.size(); i++) {
int j = p[i - 1];
while (j && s[i] != s[j]) j = p[j - 1];

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!