zcmu 1550 (наименьшее представление строки)

Ссылка на заголовок: https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1550

Тема

Дайте вам строку s, она может вращаться влево, и попросите, чтобы строка была наименее лексикографически после того, как несколько раз сдвинула ее влево.

Цикл влево, например s is (adac), тогда сдвиг влево может быть adac, daca, acad, cada. Наименьший лексикографический порядок здесь - acad, поэтому его нужно сдвинуть влево 3 раза.

Идеи

O (n ^ 2) будет тайм-аут, вот подход O (n)

i, j - два указателя, указывающие позицию первой буквы из двух строк. k представляет собой самую длинную общую длину префикса двух строк. Поскольку два массива необходимо сравнивать в лексикографическом порядке, i и j не могут быть одинаковыми, i инициализируется значением 0, j инициализируется значением 1, а k инициализируется значением 0

Когда s [i + k] == s [j + k], длина k как общего префикса увеличивается на 1.

Когда s [i + k]> s [j + k], я перепрыгну на k + 1, чтобы достичь позиции i + k + 1.

Когда s [i + k] <s [j + k], j перескочит на k + 1, чтобы достичь позиции j + k + 1, почему?

На что мы должны обратить внимание, так это на то, что в строке с наименьшим лексикографическим порядком должны быть строки одинаковой длины, начиная с s [i + 1 до j-1], которые не меньше, чем строки, начинающиеся с s [i] , иначе i уже давно перескочил назад, то если s [i + k]> s [j + k], то это означает, что нижний индекс, начинающийся с j, имеет меньший лексикографический порядок длины k

Затем необходимо настроить i. Поскольку длина строки, начинающейся с j, равна k, то k позиций после начала i не нужно запускать, потому что они не будут меньше текущей строки, начинающейся с j, поэтому i пришлось перескочить на k + 1 позицию. Если s [i + k] <s [j + k], то же самое верно.

Затем, чтобы убедиться, что i и j не могут быть одинаковыми, нам нужно судить. Если они одинаковы, мы принимаем j ++, и, наконец, лексикографический порядок строки длины n, начинающейся с i, должен быть наименьшим.

код переменного тока

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 3e5 + 5;
char s[maxn];
int cal(int n){
    int i = 0, j = 1, k = 0;
    while(i < n && j < n && k < n) {
        int c1 = (i + k) % n, c2 = (j + k) % n;
        if(s[c1] == s[c2]) k ++;
        else {
            if(s[c1] < s[c2]) j += k + 1;
            else i += k + 1;
            if(i == j) j ++;
            k = 0;
        }
    }
    return i;
}
int main(){
    int t; scanf("%d",&t);
    while(t --){
        scanf("%s", s);
        printf("%d\n", cal(strlen(s)));
    }
    return 0;
}

Дополнительный вопрос

Другой похожий вопрос  P1368 [Template] Minimal Notation

Можно сказать, что метод точно такой же, но он выводит строку с наименьшим лексикографическим порядком

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 3e5 + 5;
int s[maxn];
int cal(int n){
    int i = 0, j = 1, k = 0;
    while(i < n && j < n && k < n){
        int d1 = (i + k) % n, d2 = (j + k) % n;
        if(s[d1] == s[d2]) k ++;
        else{
            if(s[d1] > s[d2]) i += k + 1;
            else j += k + 1;
            if(i == j) j ++;
            k = 0;
        }
    }
    return i;
}
int main(){
    int n; scanf("%d",&n);
    for(int i = 0; i < n; i ++) {
        scanf("%d",&s[i]);
    }
    int ans = cal(n);
    for(int i = 0; i < n; i ++) {
        if(i) printf(" ");
        printf("%d", s[(i + ans) % n]);
    }
    puts("");

    return 0;
}

 

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

отblog.csdn.net/weixin_43911947/article/details/112674690