Skip to content

USACO 2023 US Open Contest Silver Division - Pareidolia#

Problem link: here

Solution Author: Stefan Dascalescu

Problem Solution#

First, you want to know for each ending position how much you need to go to the left in order to get a bessie. In order to get this done, you can create a lookup table which tells you the previous position a certain character showed up.

After we did this, we can now define \(dp[i]\) as the answer for the substrings ending at position \(i\). Let x be the position (0-indexed) up to which we need to go backwards for a bessie.

Then, \(dp[i] = (dp[x] \ if \ x \geq 0) + (x + 2)\), as we are off by one because of the indexing and off by one because we take the previous position before it all ended.

Source code#

The source code in C++ can be seen below.

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::string;

char lit[] = {'b', 'e', 's', 'i'};
int target[] = {0, 1, 2, 2, 3, 1};

int n, prv[4][300002];
long long dp[300002], ans;

int main() {
    string s;
    cin >> s;

    n = s.size();

    for (int i = 0; i <= 3; i++) prv[i][0] = -1;

    for (int i = 0; i < n; i++)
        for (int poz = 0; poz <= 3; poz++)
            if (s[i] == lit[poz])
                prv[poz][i] = i;
            else 
                if (i > 0)
                    prv[poz][i] = prv[poz][i - 1];

    for (int i = 0; i < n; i++) {
        int x = i;
        int tgt = 5;
        while (tgt >= 0 && x >= 0) {
            int poz = prv[target[tgt]][x];
            if (poz != -1) 
                tgt--;
            x = poz - 1;
        }
        if (tgt == -1) {
            dp[i] += (x + 2);
            dp[i] += dp[x];
        }
        ans += dp[i];
    }

    cout << ans << '\n';
    return 0;
}