1

这是我很难解决的问题。

给定一个密文 Y 和从字符串 Z 产生 Y 的循环移位序列,带有参数 (i, j, k) 的移位适用于子字符串 Z[i..j](从第 i 个到 j- th 字符,包括)并循环向右旋转 k 次。字符串字符从 1 开始编号。鉴于上述信息,您的任务是猜测初始明文 X。

输入:

第一行包含密文,它是一个由 N 个小写英文字母(1 ≤ N ≤ 50000)组成的非空字符串。第二行包含班次数 M (1 ≤ M ≤ 50000)。以下 M 行描述了循环移位的序列(按照它们应用于明文的顺序)。每个移位由三个参数 i、j、k (1 ≤ i < j ≤ N, 1 ≤ k ≤ j - i) 描述。

输入示例:

logoduck 
3
1 3 1 
4 5 1 
1 4 1

作为输出,您应该提供解密的文本(例如“goodluck”)。

显而易见的方法是尝试从最后一个班次开始反转每个班次。这种方法似乎不省时。但是,我无法想出如何以其他方式做到这一点的任何想法,因此不胜感激。

我附上我的代码:

#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;
}
4

1 回答 1

2

您可以使用称为“绳索”的数据结构在 O(M log N) 时间内完成此操作,这就像一个支持在 O(log N) 时间内拆分和连接的字符串:https ://en.wikipedia.org/ wiki/绳索_(数据结构)

当然,可以从这些操作中构建轮换。

该实现是二叉树、B-tree 或类似的,在叶子中具有有限大小的字符串。

找到 C++ 实现并不难,但不幸的是,STL 没有。如果你必须自己实现它,这有点棘手。

于 2020-12-18T13:45:45.733 回答