問題の発生源ません文字列いいえ(POIに思える何?) - 最小限の表現

説明] [タイトルが
長さのあなたに2を与える\(N- \) 2つの文字列が等しくなるように、文字列は、バックに文字列で文字列の接頭辞かどうかを尋ねました。その場合は、上記の操作で得られた辞書順最小の文字列を出力できるが必要な場合があります。
[入力形式を
第一列の二つの整数\(N、T \)
長さの次の2行\(N- \)文字列。

[出力形式]
その場合、出力\(TAK \) そうでない場合は、出力\(NIE \) もし\(。1 = T \) あなたは次の辞書順最小を必要とする文字列の出力ライン。

データ範囲は[]
\(Nル\ 1000000 \)

まず、何である(TAK \)\
自分のBaiduの翻訳

元の文字列が1つの巡回シフトに相当しますので、文字列の接頭辞をバック受け取る暴力の実践について考えてみて、あなたはすべての巡回シフトを列挙することができます。
時間複雑\(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
おすすめ