cppAcademy
FROM LEARNING TO COMPETING

Real problems.
Your next challenge.

Explore the Group C Olympiad and Autumn Tournament archive.
Choose a topic. Find a challenge. Build your solution.

274 tasks: 213 from the Municipal, Regional, and National Olympiad rounds (2009–2026), 57 Autumn Tournament tasks (2007–2025), and 4 previously featured problems. 207 tasks have independently written English summaries, analyses, and C++17 solutions; the remaining entries link to Arena. Difficulty labels are learning estimates, not official ratings. Special formats and source clarifications are explained on affected tasks.
GROUP C2025 · MediumSubsequence matching

Recover the Special Letter

Autumn Tournament (2025)

Submission name: special.cpp

Problem summary

Exactly one character of S was changed to a different letter, then arbitrary letters were inserted to form P. Recover any valid1-based changed position and replacement letter.

Input

Strings S and P on separate lines.

Output

A1-based position in S and the different replacement letter.

Constraints

1 ≤ |S| ≤ |P| ≤ 1000000; lowercase Latin letters; at least one solution exists.

Worked example

Original statement sample; constructive output may differ when any valid answer is accepted.

Input

aaabaaa
aaacaaa

Output

4 c

Solution analysis

  1. Greedily match every prefix of S as early as possible in P. Store left[i], the earliest P position where the prefix before S[i] finishes; use−1 for the empty prefix. Independently match suffixes backward, storing right[i+1], the latest position where the suffix after S[i] can start.
  2. Changing position i works exactly when a letter different from S[i] exists strictly between those two boundaries. There is no need to scan that gap repeatedly: precompute nextDifferent[j], the next index after j whose character differs from P[j]. For a gap beginning at j, either P[j] already differs or nextDifferent[j] is its first differing candidate.
  3. For S=aaabaaa and P=aaacaaa, the prefix aaa ends at index2 and the suffix aaa starts at index4. The one-position gap contains c, which differs from b, so the answer is4 c. The prefix/suffix scans are linear even when many equal letters repeat.

Why it works

Any embedding after changing S[i] has its preceding prefix no earlier than the greedy earliest prefix endpoint and its suffix no later than the greedy latest suffix start. Thus its changed character must fit in the computed gap. Conversely, a different character in that gap joins the two greedy embeddings into a valid result. Testing all positions therefore finds a promised solution.

Complexity: O(|S|+|P|) time and space. Prefix and suffix matches and next-different runs each require one scan; every candidate position is checked in O(1).

Watch out. The replacement must differ from the original letter even if S already is a subsequence of P. Require valid prefix and suffix embeddings before using a gap. Print the S position, not the index in P.

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 source,result;
    cin>>source>>result;
    int n=static_cast<int>(source.size());
    int m=static_cast<int>(result.size());
    vector<int>left(n+1,m);
    vector<int>right(n+1,-1);
    left[0]=-1;
    int position=0;
    for(int i=0;i<n;i++){
        while(position<m&&result[position]!=source[i]){
            position++;
        }
        if(position==m){
            break;
        }
        left[i+1]=position++;
    }
    right[n]=m;
    position=m-1;
    for(int i=n-1;i>=0;i--){
        while(position>=0&&result[position]!=source[i]){
            position--;
        }
        if(position<0){
            break;
        }
        right[i]=position--;
    }
    // Skip a whole equal-letter run when looking for a changed character.
    vector<int>nextDifferent(m,m);
    for(int i=m-2;i>=0;i--){
        nextDifferent[i]=result[i+1]!=result[i]?i+1:nextDifferent[i+1];
    }
    for(int i=0;i<n;i++){
        if(left[i]==m||right[i+1]==-1){
            continue;
        }
        int candidate=left[i]+1;
        if(candidate<right[i+1]&&result[candidate]==source[i]){
            candidate=nextDifferent[candidate];
        }
        if(candidate<right[i+1]){
            cout<<i+1<<' '<<result[candidate]<<'\n';
            return 0;
        }
    }
}

Source: Arena Olimpiici ↗