Нет источник проблемы (Что, кажется, POI) строку - минимальное представление

Описание] [Название
даст вам две длину \ (п \) строка спрашивает , может ли префикс строки строки в спину так , что две строки равны. Если да, то вам может потребоваться выход лексикографически наименьший строка символов , полученный с помощью описанной выше операции может быть.
[Формат ввода
два целых числа первого ряда \ (п, Т \) .
Следующие две строки длины \ (п \) строки.

[Формат вывода]
Если да, то выход \ (TAK \) , в противном случае выход \ (NIE \) . Если \ (. 1 = Т \) , выходная линия строки вам нужно лексикографически наименьший следующий.

Диапазон данных []
\ (\ п ле 1 млн \)

Во- первых, что \ (TAK \) ?
Собственный Baidu перевод

Подумайте о практике насилия получит обратно префикс строки , так что исходная строка соответствует одному циклическому сдвигу, так что вы можете перечислить все циклический сдвиг.
Сложность времени \ (O (N ^ 2) \)

在这里介绍一种\(O(n)\)求出一个字符串最小的循环移位的方法
先将原串复制一遍加在原串后面 即 将\(ABCD\) 变为 \(ABCDABCD\) 这样在这个新字符串中任意取一段长为\(n\)的子串一定是原串的一种循环移位。
维护两个指针\(i, j\)和当前子串长度\(len\),表示现在正在比较从\(i\)开始的长度为\(len+1\)的子串和从\(j\)开始的长为\(len+1\)的子串。
若某一时刻,\(s[i+len] \neq s[j+len]\)
\(s[i+len] < s[j+len]\),则说明从\(i\)开始的子串比从\(j\)开始的子串小,所以最小子串一定不会从\(j\)开始。此时可以直接让\(j = j + len + 1\),然后继续匹配。
反之让\(i = i + len + 1\)
为什么这样可以保证正确性呢?
反证:如果此时 \(s[i+len] < s[j+len]\) ,即\(j\)被“淘汰”了,假设最小子串其实是从\(s[j+k](1 \le k \le len)\)开始的,那么一定存在从\(s[i+k]\)开始的子串会比它小。
举例:"\(ABAABBC\)": 此时\(i\)\(s[1]\)\(j\)\(s[4]\)\(len=2\)时发现\(s[1+2] < s[4+2]\),所以\(j\)可以直接跳到7。因为从\(S[5], S[6]\)开始的子串一定不会成为最小的。对于从\(s[5]\)开始的"\(BBC\)..."有从\(s[2]\)开始的"\(BA\)..."比它小,从\(s[6]\)开始的\(s[3]\)一定比它小。

【代码实现】

#include <bits/stdc++.h>
#define ri register int
using namespace std;

inline int read() {
    int ret = 0, flag = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') flag = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        ret = (ret << 1) + (ret << 3) + (ch ^ '0');
        ch = getchar();
    }
    return ret * flag;
}
 
int n, t;
int i, j;
int min1, min2;
char s1[2000005], s2[2000005];
bool yes = 1;

int main() {
    n = read(); t = read();
    scanf("%s", s1+1);
    scanf("%s", s2+1);
    for (ri a = 1; a <= n; a++) {
        s1[a + n] = s1[a]; 
        s2[a + n] = s2[a];
    }
    i = 1; j = 2;
    while (i <= n && j <= n) {
        if (i == j) j++;
        for (int len = 0; ; len++) {
            if (s1[i+len] < s1[j+len]) {
                j = j + len + 1;
                break;
            }
            if (s1[j+len] < s1[i+len]) {
                i = i + len + 1;
                break;
            }
        }
    }
    if (i <= n) min1 = i;
    else min1 = j;
    i = 1; j = 2;
    while (i <= n && j <= n) {
        if (i == j) j++;
        for (int len = 0; ; len++) {
            if (s2[i+len] < s2[j+len]) {
                j = j + len + 1;
                break;
            }
            if (s2[j+len] < s2[i+len]) {
                i = i + len + 1;
                break;
            }
        }
    }
    if (i <= n) min2 = i;
    else min2 = j;
    for (ri len = 0; len < n; len++) {
        if (s1[min1 + len] != s2[min2 + len]) {
            yes = 0;
            break;
        }
    }
    if (yes) {
        puts("TAK");
        if (t) {
            for (ri a = min1; a <= min1 + n - 1; a++) {
                putchar(s1[a]);
            }
            puts("");
        }
        
    } else puts("NIE");
    return 0;
} 

рекомендация

отwww.cnblogs.com/ak-dream/p/AK_DREAM6.html