Блог пользователя kb.

Автор kb., 12 лет назад, По-русски

Здравствуйте! Недавно пытался сдать простую задачу, в которой нужно было посчитать суфмасс для циклических сдвигов строки, а по нему — lcp. Код построения суфмасса почти идентичен размещенному на e-maxx.ru в соответствующей статье. Lcp строил алгоритмом Касаи, но длительное время получал WA. После того, как я посортил куски суфмасса, находящиеся в одном классе эквивалентности, по убыванию индекса (т.е. по возрастанию длины), решение внезапно получило AC. Позже, я встретил похожую задачу, и опять все повторилось, спас только этот грязный хак с сортировкой. Теперь очень захотелось разобраться, что же я делаю не так. Возможно, это спецэффект Касаи, о котором нигде не написано? Или я криво его пишу? В любом случае, вот мой код. Прошу помочь разобраться!

  • Проголосовать: нравится
  • +11
  • Проголосовать: не нравится

»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

для циклических сдвигов лцп не работает, вроде на тесте abab какая-то хрень

»
12 лет назад, # |
  Проголосовать: нравится +19 Проголосовать: не нравится

Тут надо плясать от доказательства Кассаи. Оно использует факт, что если i раньше j, то i+1 раньше j+1. Для циклических сдвигов это неверно. Надо просто это проверять и если что сбрасывать накопленный результат. Это случится O(1) раз.

  • »
    »
    12 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Вот проблема как раз таки из-за того, что я плохо понимаю, почему Касаи (на википедии все-таки с одной "с") вообще работает. А вот обозначения i и j, это имеется ввиду как в коде, т.е. текущий суффикс и следующий в суфмассе? Видимо, делая сортировку по убыванию, я правильного порядка невольно и добивался?

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится +3 Проголосовать: не нравится

      Казалось бы они сами будут отсортированы по неубыванию, т.к. сортировка стабильная. Так что странно.

      Под i,j имеются ввиду два соседних суффикса в суфмассиве. Там случается проблема с последним, и она есть в любом случае для циклических сдвигов.

      • »
        »
        »
        »
        12 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        Однако код без магических строчек

        int lstPos = 0;
        for (int i = 0; i <= n; i++)
        	if (i == n || c[p[i]] != c[p[i - 1]])
        	{
        		sort(p + lstPos, p + i, greater<int>());
        		lstPos = i;
        	}
        

        получает WA на двух разных джаджах по двум разным задачам, а с ними — AC

        • »
          »
          »
          »
          »
          12 лет назад, # ^ |
            Проголосовать: нравится +3 Проголосовать: не нравится

          А. По убыванию. Ну да. Это что-то меняет. Хотя, почему все становится хорошо, мне все равно не понятно.

»
12 лет назад, # |
Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

можете не заморачиваться (хотя разобраться всегда интересно), если вам надо находить lcp для двух циклических сдвигов, можно сделать так: построить суффмассив на строке s+s+#, посчитать лсп, и когда надо найти лсп двух сдвигов — просто взять минимум на отрезке массива lcp

  • »
    »
    12 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Ну хотелось бы иметь нормальный массив lcp все-таки, и ведь по сути это тоже хак, ни чем не лучше предложенного мной

    • »
      »
      »
      12 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      ну да, ну просто ваш хак я не понимаю) почему он работает