@fjaerj12

Что не так с решением задачи?

Задача
Вася недавно узнал, что такое циклическое k-расширение строки S. Его можно получить следующим образом: склеить k экземпляров строки S, а потом взять первые k символов результата.

Узнав это, Вася обрадовался, взял некоторую строку, и начал к ней применять описанную операцию, не запоминая, какое он каждый раз брал k.

Вам дана часть строки, получившейся у Васи. Ваша задача определить, не ошибся ли Вася в своих сложных преобразованиях, т. е., мог ли у него из первоначальной строки получиться ответ, содержащий данную строку в качестве подстроки.

Входные данные
В первой строке входного файла INPUT.TXT находится изначальная строка, которую Вася бережно записал перед тем, как приступить к своим действиям. Во второй строке находится подстрока результата, полученного Васей. Обе строки не пусты и по длине не превышают 5 000 символов. Строки могут состоять из больших и маленьких английских букв (с учетом регистра), а также цифр.

Выходные данные
В выходной файл OUTPUT.TXT выведите "NO", если можно точно сказать, что Вася ошибся, и "YES", если мог и не ошибиться.

Примеры
1) Вход:
abc
abc
Выход:
YES
2) Вход:
abcd
bcabc
Выход:
YES
3) Вход:
abcabc
abcA
Выход:
NO

Идея
Я подумал, что задача заключается в том, чтобы проверить, есть ли в первой и второй строках одинаковые значения, но, видимо, неправильно.
#include <iostream>
#include <string>

int main()
{
    std::string str;
    std::string substring;

    std::cin >> str;
    std::cin >> substring;

    bool check = false;

    int i = 0;
    while (!check && i < substring.length())
    {
        if (str.find(substring[i]) == std::string::npos)
        {
            check = true;
        }
        i++;
    }
    if (check)
    {
        std::cout << "NO";
    }
    else
    {
        std::cout << "YES";
    }
}
  • Вопрос задан
  • 216 просмотров
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Ваша идея не верна.

Надо порисовать на бумажке и убедится, что из строки S вы можете получить только строки вида S(k1)S(k2)S(k3)...S(kn), Где S(x) - x-ый префикс строки S, т.е. первые x символов.
При этом k1 >= k2, ... k1>= kn.

При чем все строки такого вида можно получить.

Доказывается по индукции по количеству операций. Изначально строка именно такого вида (k1=длина строки). После каждой операции, эта строка сколько-то раз копируется и как-то обрезается по длине. Поэтому любая полученная строка будет такого вида. И каждую такую строку можно построить: применяйте операции с k равными k1, k1+k2, k1+k2+k3... Так вы за n операций соберете все префиксы по одному.

Теперь, раз вам во входном файле задана подстрока результата, вам надо проверить, что эта строка состоит из подстроки S, за которой идут префиксы строки S.

Так, пример из условия bcabc состоит из подстроки bc и одного префикса abc.

В задаче не очень большие ограничения, поэтому можно в тупую для каждой подстроки i..j результирующей строки определить, является ли она суффиксом первой строки. Также для каждой подстроки первой строки можно определить, является ли она префиксом второй строки.

Потом нужно построить граф: из позиции 0 сделайте ребра во все позиции, где заканчивается какая-то подстрока первой строки в начале второй. Из позиции i>0 сделайте ребра во все позиции j такие, что подстрока i...j префикс первой строки.

Потом, если в этом графе есть путь из вершины 0 в вершину с номером длины второй строки - YES. Иначе - NO.

Это решение за квадрат, если подстроки искать не совсем в тупую: для проверки на суффикс внешний цикл ведите по правому концу, а внутренний - по левому концу убывая. Так можно сдвигать второй указатель, пока строка остается суффиксом, проверяя каждый раз только один символ. Похожим образом можно проверять все подстроки на совпадение с префиксом.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы