Count Binary Runs Under Bit Flips
National Olympiad — National round (2024 season)
Submission name: bitstring.cpp
Problem summary
Maintain a binary string under Inv i flips and Print x queries. Following the complete official sample, Print counts maximal runs of the requested bit.
Source clarification. The printed statement calls these objects substrings, but its complete sample and explanation count maximal constant runs. For example, 1110110111 has three one-runs rather than fifteen all-one substrings. This solution follows that demonstrated interpretation.
Input
The binary string, command count, then Inv i or Print x. Positions are 1-based.
Output
One run count per Print command.
Constraints
1≤string length,command count≤1000000.
Worked example
Input and output for the worked example discussed below.
Input
1100111011 11 Inv 8 Inv 3 Inv 7 Print 1 Inv 5 Inv 3 Print 0 Inv 2 Inv 9 Print 0 Print 1
Output
3 2 3 4
Solution analysis
- A run starts at i precisely when i=0 or its bit differs from the previous bit. Maintain separate counters for zero-run and one-run starts.
- Flipping position i can affect only start tests i and i+1. Remove those old contributions, flip, and add the new contributions; all other comparisons remain unchanged.
- After the first three sample flips, 1110110111 has three one-runs: 111,11,111. The remaining commands produce counts 2,3,4. Each maximal run counts once regardless of length.
Why it works
The start condition identifies one position for each maximal run. Exactly the two tests using the changed bit can change, and both are recomputed. This preserves the run counts after each operation.
Watch out. Do not count all homogeneous substrings: that would contradict the source sample. Convert the 1-based flip index and check the right endpoint.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<string>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
string bits;
cin>>bits;
int runs[2]={0,0};
auto change=[&](int position,int delta){
if(position<int(bits.size())&&(position==0||bits[position]!=bits[position-1])){
runs[bits[position]-'0']+=delta;
}
};
for(int i=0;i<int(bits.size());i++){
change(i,1);
}
int commands;
cin>>commands;
while(commands-->0){
string command;
int value;
cin>>command>>value;
if(command=="Print"){
cout<<runs[value]<<'\n';
}
else{
int position=value-1;
// Only these two possible starts use the flipped bit.
change(position,-1);
change(position+1,-1);
bits[position]=bits[position]=='0'?'1':'0';
change(position,1);
change(position+1,1);
}
}
}