简体   繁体   English

反转循环移位序列

[英]Reversing a sequence of cyclic shifts

Here's the problem I have a hard time solving.这是我很难解决的问题。

You are given a ciphertext Y and a sequence of cyclic shifts that had produced Y from string Z, the shift with parameters (i, j, k) applies to the substring Z[i..j] (from i-th to j-th character, inclusive) and cyclicly rotates it to the right k times.给你一个密文 Y 和一个从字符串 Z 产生 Y 的循环移位序列,带有参数 (i, j, k) 的移位适用于 substring Z[i..j] (从第 i 个到 j- th 字符,包括)并循环向右旋转 k 次。 String characters are numbered starting from one.字符串字符从 1 开始编号。 Given the above information, your task is to guess the initial cleartext X.鉴于上述信息,您的任务是猜测初始明文 X。

Input:输入:

The first line contains the ciphertext, which is a nonempty string consisting of N lowercase English letters (1 ≤ N ≤ 50000).第一行包含密文,它是一个由 N 个小写英文字母(1 ≤ N ≤ 50000)组成的非空字符串。 The second line contains the number of shifts M (1 ≤ M ≤ 50000).第二行包含班次数 M (1 ≤ M ≤ 50000)。 The following M lines describe the sequence of cyclic shifts (in the order of their application to the cleartext).以下 M 行描述了循环移位的序列(按照它们应用于明文的顺序)。 Each shift is described by three parameters i, j, k (1 ≤ i < j ≤ N, 1 ≤ k ≤ j − i).每个移位由三个参数 i、j、k (1 ≤ i < j ≤ N, 1 ≤ k ≤ j - i) 描述。

Example of input:输入示例:

logoduck 
3
1 3 1 
4 5 1 
1 4 1

As output you should provide the deciphered text (``goodluck'' for example).作为 output 您应该提供解密的文本(例如“goodluck”)。

The obvious approach is to try and reverse each shift starting from the last one.显而易见的方法是尝试从最后一个班次开始反转每个班次。 It seems that this approach is not time-efficient.这种方法似乎不省时。 However, I can't come up with any ideas how to do it any other way, so any help is appreciated.但是,我无法想出如何以其他方式做到这一点的任何想法,因此不胜感激。

I attach my code:我附上我的代码:

#include <iostream>
#include <vector>
#include <string>


int main() {

    std::string message;
    std::cin >> message;

    int number_of_elements = message.size();
    int elements[number_of_elements];
    for (int i = 0; i < number_of_elements; ++i) {
        elements[i] = i;
    }

    int number_of_shifts;
    std::cin >> number_of_shifts;
    std::vector<std::vector<int>> shifts(number_of_shifts);

    for (int iterator = 0; iterator < number_of_shifts; ++iterator) {
        int left, right, by;
        std::cin >> left >> right >> by;
        --left;
        --right;
        shifts[iterator].push_back(left);
        shifts[iterator].push_back(right);
        shifts[iterator].push_back(by);
    }

    for (int iterator = number_of_shifts - 1; -1 < iterator; --iterator) {
        int current[number_of_elements];
        int left, right, by;
        left = shifts[iterator][0];
        right = shifts[iterator][1];
        by = shifts[iterator][2];


        for (int j = right; left - 1 < j; --j) {
            if (j - by < left) {
                current[right + 1 - (left - (j - by))] = elements[j];
            } else {
                current[j - by] = elements[j];
            }
        }

        for (int j = left; j < right + 1; ++j) {
            elements[j] = current[j];
        }
    }

    for (int i = 0; i < number_of_elements; ++i) {
        std::cout <<  message.substr(elements[i], 1);
    }

    return 0;
}

You can do this in O(M log N) time using a data structure called a "rope", which is like a string that supports splitting and concatenation in O(log N) time: https://en.wikipedia.org/wiki/Rope_(data_structure)您可以使用称为“绳索”的数据结构在 O(M log N) 时间内完成此操作,这就像一个支持 O(log N) 时间内拆分和连接的字符串: https://en.wikipedia.org/ wiki/绳索_(数据结构)

Rotations can be build from these operations, of course.当然,可以从这些操作中构建轮换。

The implementation is a binary tree, B-tree, or similar with limited-size strings in the leaves.该实现是二叉树、B-tree 或类似的,在叶子中具有有限大小的字符串。

It's not hard to find C++ implementations, but unfortunately, the STL doesn't have one.不难找到 C++ 实现,但不幸的是,STL 没有。 If you have to implement it yourself, it's a little tricky.如果你必须自己实现它,这有点棘手。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM