Codeforces: Rudolph and the ugly line

Diana Begdesenova
2 min readMar 18, 2024

--

When I was scrolling through problems with 900 difficulty, I came across a very interesting problem on Codeforces named “Rudolph and the ugly line” (1941C).

Here are the conditions of the problem:

Rudolf has a string s length n. Rudolf believes that the string s is ugly if contains as substring at least one string «pie» or at least one string «map», otherwise the string s will be beautiful.

For example, «ppiee», «mmap», «dfpiefghmap» are ugly strings, and «mathp», «ppiiee» are beautiful strings.

Rudolf wants to shorten s by removing some characters to make it look beautiful.

The protagonist does not like to strain, so asks you to make the string beautiful while removing the minimum number of characters. It can remove characters from any line position (not just from the beginning/end of the line).
String a is a substring of b if in line b there is a consecutive line of characters equal a.

Input
The first line contains a single integer t(1 t 104) — the number of input datasets. The following are descriptions of the datasets.

The first line of the set contains a single integer n
(1 n 106) — string length s.

The next row of the set contains the string s length n. String s
consists exclusively of lowercase Latin letters.

Sum n for all input data sets not exceeding 106.

Output
For each input set, print a single integer — the minimum number of characters that you want to delete to string s
became beautiful. If the string is initially beautiful, print 0.

To solve this problem you need to find all substrings «pie», «map», «mapie» in the string s and remove the middle character in them. Thus, we will remove the minimum number of characters so that the substrings «pie» and «map» do not meet in the string.

Here is my code:

#include <iostream>
#include <string>

using namespace std;

int main() {
long long t;
cin >> t;

for (long long c = 0; c < t; c++) {
long long n;
cin >> n;

string s;
cin >> s;

int count = 0;
for (string sul : {"mapie", "pie", "map"}) {
size_t pos = 0;
while ((pos = s.find(sul, pos)) != string::npos) {
s[pos + sul.length() / 2] = '?';
count++;
pos += sul.length();
}
}

cout << count << endl;
}

return 0;
}

Search and replace fragments cycle:

for (string sul : {"mapie", "pie", "map"}) {
size_t pos = 0;
while ((pos = s.find(sul, pos)) != string::npos) {
s[pos + sul.length() / 2] = '?';
count++;
pos += sul.length();
}
}

In this cycle all fragments “mapie”, “pie” and “map” are sorted. A nested while loop starts for each fragment and searches for it in the s string. If a fragment is found, the symbol in its middle is replaced with ? and the count counter increases. Then the while loop continues to search from the next position after the fragment found.

--

--