cppAcademy
FROM LEARNING TO COMPETING

Expert.
Put your skills to the test.

Bulgarian Informatics Group A · 2007–2026

274 independently explained problems: 54 Municipal, 54 Regional, 109 National Olympiad and 57 Autumn Tournament tasks. Difficulty labels are learning estimates, not official ratings. Some events share Senior/IATI or Group A/B problem sets. Special formats, scoring limitations and source clarifications are explained on affected tasks. Existing shared National-round problems keep their permanent URLs.
GROUP A2008 · HardDuval algorithm and Lyndon words

Lyndon Factorization of a String

Autumn Tournament (2008)

Submission name: string.cpp

Problem summary

Split a lowercase string into consecutive simple words in nonincreasing lexicographic order. A word is simple when it is strictly smaller than every nonempty proper suffix. Print the number and lengths of the factors.

Input

One nonempty lowercase Latin string.

Output

The factor count followed by the length of every factor.

Constraints

String length≤1000000.

Worked example

Original statement sample.

Input

baabaaabba

Output

4 1 3 5 1

Solution analysis

  1. A simple word is also called a Lyndon word. Duval’s algorithm maintains a candidate beginning at i, scans ahead with j, and compares against a position k inside the candidate. Equal characters extend a possible repetition; a larger new character resets k to i.
  2. When the next character is smaller, the candidate cannot extend while preserving the Lyndon property. Its fundamental block length is j−k. Output that block repeatedly while its starting position is at most k, then begin the next candidate. This is why repeated patterns do not cause repeated rescanning of every suffix.
  3. The sample factors are b | aab | aaabb | a, with lengths1,3,5,1. Each factor is smaller than its proper suffixes, and b≥aab≥aaabb≥a. A string of identical letters produces one-character factors; an increasing string such as abcd is one factor.

Why it works

During the inner scan, the examined prefix consists of repetitions of one Lyndon candidate followed by a prefix of it. A smaller next character fixes the candidate’s period and prevents it from extending. Emitting those copies produces the maximal first Lyndon factor(s), after which the same invariant applies to the remaining suffix. This is the Chen–Fox–Lyndon factorization, whose factors are nonincreasing.

Complexity: O(L) time and O(L) space including the input and output factor-length list. The scan positions advance amortized linearly; the algorithm does not compare all suffix pairs.

Watch out. The comparison in the inner loop is ≤, while a strictly larger next character resets k. Reversing the inequalities computes a different factorization. Count repeated one-character factors individually.

Commented C++17 solution

An independently written complete program with standard headers.

#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string text;
    cin>>text;
    int n=static_cast<int>(text.size());
    vector<int>lengths;
    int start=0;
    while(start<n){
        int scan=start+1;
        int matched=start;
        while(scan<n&&text[matched]<=text[scan]){
            if(text[matched]<text[scan]){
                matched=start;
            }
            else{
                matched++;
            }
            scan++;
        }
        int length=scan-matched;
        // Emit every completed repetition of this Lyndon block.
        while(start<=matched){
            lengths.push_back(length);
            start+=length;
        }
    }
    cout<<lengths.size();
    for(int length:lengths){
        cout<<' '<<length;
    }
    cout<<'\n';
}

Source: Arena Olimpiici ↗