GDST - Editorial

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4

Author: hellolad
Tester: watoac2001
Editorialist: iceknight1093

DIFFICULTY:

TBD

PREREQUISITES:

None

PROBLEM:

A binary string is called good if it can be partitioned into several substrings, each of even length, and each containing the same character.

You’re given a binary string S of even length.
Exactly once, you can choose an alternating subsequence of S, and flip it.
Find a way to make S good using such a move, or claim it’s impossible.

EXPLANATION:

First, let’s analyze what exactly it means for a string to be good.
Suppose S can be partitioned into even-length substrings, each containing the same character within themselves.
Notice that we can go even finer: each even-length substring can be broken up into a bunch of substrings of length 2, and we’ll still have a valid partition.

So, if S is good, it can be broken up into length 2 substrings, each consisting of the same character twice.
Notice that this is only possible when S_{2i} = S_{2i-1} for each 1 \leq i \leq \frac{N}{2}, i.e, the first character should equal the second, the third should equal the fourth, and so on.
Clearly, a string that’s in such a form is also good, since it can be broken up into the corresponding length 2 substrings to form a valid partition.

So, S is good if and only if S_{2i} = S_{2i-1} for each possible i.

Now, let’s see how we can get S into this form.
If S_{2i} = S_{2i-1} for some i, to maintain this we should either flip both of them, or neither of them.
Flipping both isn’t possible since the chosen subsequence wouldn’t be alternating; so our only choice is to flip neither.

If S_{2i} \neq S_{2i-1}, we need to flip either index 2i or index 2i-1, but not both.
Suppose there are K pairs of such indices (2i-1, 2i), such that one of them needs to be flipped.
These pairs are disjoint, so we’ll need to choose a subsequence of length exactly K; one index from each pair.

Now, it’s always possible to choose an alternating subsequence - since each pair contains one 0 and one 1, choose the position of the 0 from the first pair, the 1 from the second pair, the 0 from the third pair, and so on.

TIME COMPLEXITY:

\mathcal{O}(N) per testcase.

CODE:

Author's code (C++)
#include <bits/stdc++.h>
using namespace std;
#define IOS ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define ll long long

int main(){
    IOS
    int t;
    cin>>t;
    while(t--){
        int n;
        string s;
        cin>>n>>s;
        int cnt=0;
        for(int i=0;i<n;++i){
            cnt+=s[i]=='1';
        }
        vector<int> subs={n};
        cnt=1;
        s.push_back('#');
        for(int i=1;i<=n;++i){
            if(s[i]==s[i-1]){
                cnt++;
            }else{
                if(cnt&1){
                    if(s[i-1]==s[subs.back()]){
                        subs.push_back(i);
                        cnt=1;
                        i++;
                    }else{
                        subs.push_back(i-1);
                        cnt=2;
                    }
                }else{
                    cnt=1;
                }
            }
        }
        cout<<subs.size()-1<<'\n';
        for(int i=1;i<subs.size();++i){
            cout<<subs[i]+1<<' ';
        }
        cout<<'\n';
    }
    return 0;
}
Editorialist's code (Python)
for _ in range(int(input())):
    n = int(input())
    s = input().strip()
    ind = []
    for i in range(0, n, 2):
        if s[i] != s[i+1]: ind.append(i)
    print(len(ind))
    ans = []
    for i in range(len(ind)):
        if i%2 == 0:
            if s[ind[i]] == '0': ans.append(ind[i]+1)
            else: ans.append(ind[i]+2)
        else:
            if s[ind[i]] == '1': ans.append(ind[i]+1)
            else: ans.append(ind[i]+2)
    print(*ans)
2 Likes

explain how you can make 0101 good in one operation

I dont understand

“You can choose an alternating subsequence of S” is a fancy way to say you can flip every element you want while their adjacent element is different.

“10” is a subsequence of “0101”, then you flip both to get “0011”

  • The even length substrings of a single element are “00” and “11”
  • “10” is alternating
2 Likes

This problem kinda has two subtasks:

  1. Make the string a concatenation of even length strings made out of a single element. Say:

“000011” is good because is made out of 2 even length substrings of a single element, which are “0000” and “11”.

  1. Choose the needed indexes to flip to make it good. That subsequence must be alternating.

If you have “010101” you can choose indexes 1,3 and 5 (1-based). The subsequence to flip would be “000”. After flipped, the string would be “111111”.
But that won’t be a right answer because you need the subsequence be alternating.

You can choose indexes 1,4 and 5. The subsequence would be “010”. After flipped, the string would be “110011” and it’s good because is made out of 3 substrings made out of one element “11”, “00” and “11”.

To solve it, it would’ve been a good idea to manipulate the string as many groups of pairs (due the N is even always). Now, just detect if pairs have the same element.

In “010101” there would be 3 pairs “01”, “01” and “01”.
The 3 of them need reparation.

  1. Choose any of 0 and 1 of the first pair.
  2. To keep the alternating thing, if you chose 0 in the first, then choose 1 in the second
  3. If you chose 1 in the second, then 0 in the third.

This will always work.

#include <bits/stdc++.h> 
#define ll long long 
using namespace std; 

void solve(){ 

    ll N;
    string S;
    cin >> N;
    cin >> S;
    
    vector<ll> indexes_to_flip;
    
    char prev = '0';
    
    for(ll i=0; i<N; i+=2){
        // If they need reparation...
        
        if (S[i] != S[i+1]){
            // Check the last chosen
            // Take a a different from the prev
            
            if (prev == '0' && S[i] == '0'){
                indexes_to_flip.push_back(i+2);
                prev = '1';
            }
            
            else if (prev == '0' && S[i] == '1'){
                indexes_to_flip.push_back(i+1);
                prev = '1';
            }
            
            else if (prev == '1' && S[i] == '0'){
                indexes_to_flip.push_back(i+1);
                prev = '0';
            }
            else if (prev == '1' && S[i] == '1'){
                indexes_to_flip.push_back(i+2);
                prev = '0';
            }
        }
    }
    
    cout << indexes_to_flip.size() << "\n";
    for (auto i : indexes_to_flip){
        cout << i << " ";
    }
    cout << "\n";

} 

int main() { 
    ios_base::sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL); 
    int T; 
 
    cin >> T; 
    while(T--){ 
        solve(); 
    } 
}
2 Likes

include <bits/stdc++.h>
using namespace std;

define ll long long int
define fr(i,k,n) for(int i = k;i<n;i++)
define vll vector
define pb push_back
define sz size
template <typename T_container, typename T = typename enable_if<!is_same<T_container, string>::value, typename T_container::value_type>::type>
ostream &operator<<(ostream &os, const T_container &v)
{
for (const T &x : v)
os << x << " ";
return os << endl;
}
int32_t main(void)
{
// cin.tie(nullptr)->sync_with_stdio(false);
#ifdef LOCAL
[[maybe_unused]] FILE *in = freopen(“input.txt”, “r”, stdin);
[[maybe_unused]] FILE *out = freopen(“output.txt”, “w”, stdout);
#endif
cout << fixed << setprecision(12);
// sieve();
ll tc = 1;
cin>>tc;
while (tc-- > 0)
{
ll n;
cin>>n;
string s;
cin>>s;
bool odd = 0;
ll j = -1;
fr(i,0,n){
if(s[i]!=s[0]) {odd = i%2;j = i;break;}
}
if(j==-1) {
cout<<0<<endl;
continue;
}
char prev = s[j];
vll ans;
if(odd) ans.pb(j);
fr(i,j,n){
if(s[i]!=prev) {
if(odd&&((i-j)%2)) {odd = 0;}
else if(odd) {ans.pb(i);odd = 1;}
else if(!odd) {
odd = (i-j)%2;
if(odd) ans.pb(i);
}
prev = s[i];
}
}
cout<<sz(ans)<<endl;
cout<<ans;

}

// ---------------- PREFIX SUM ---------------------------
// ll hsh[n];
// hsh[0]=arr[0];
// for(ll i = 1; i < n; ++i)
// {
//      hsh[i]=hsh[i-1]+arr[i];
// }

// ---------------- SUFFIX SUM ---------------------------
// hsh[n-1]=arr[n-1];
// for(ll i = n-2; i >= 0; --i)
// {
//      hsh[i]=hsh[i+1]+arr[i];
// }
// assert(getchar()==-1);
cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

return 0;

}

where is my code incorrect i used following logic

case1:- - - - odd odd - - - - - : in this taking last index of first odd will give both even length
case2: -----odd even even odd------- : in this case taking last index of ( first odd and next even and next even and so on) and not taking last one odd gives all even length final substrings

1 Like

I did think of similar logic but ended up discarding the approach as it gets more complex as we get more combinations like “OOEEEEEEOEEOE” where managing indices, finding patterns like OO and OEE…O and then picking alternating patterns of values for indices picked seems overly complicated. This was my thought procedure.

The logic given in editorial achieves the same by viewing in blocks of 2.:fire:(Simply amazing​:astonished:).

// n is even hence even number of odd length and even length sets of same elements in continuity.
// i.e. 111 00 1111 0  has 4 sets (111), (00), (1111), (0)
//      parity of length of sets   Odd    Even  Even   Odd 
//
//      Now we focus on arrangements of parities possible. 
//      1. when 2 odds together -  111 00000   ----> 110 00000    or 111 10000 (just 1 change) [NOTE : depending on which index was selected the cahnge will vary in subsequent and previous indices]
//
//      2. When 1 or more evens together with no odds guarding them - 11 0000 (no operation)
//
//      3. When 1 or more evens exist between 2 odd sets - 111 00 11 0000 1 
//                               possible operation 1 :-   110 01 10 0001 1 (4 operations)
//                               possible operation 2 :-   111 10 01 1000 0 (4 operations)
//                               i.e. either leave first or last odd set untouched
  // 
  // a mixed example :-  00 111 00 1111 0 111 0 
  //                     E   O  E   E   O O   O
  //
  // Approach 1 :-       00 110 01 1110 0 111 1 (since in O E E O case last changed was 1 so in O O case we need to change a 0 somewhere )
  // Approach 2 :-       00 111 10 0111 1 110 0

My solution as per editorial approach :- my solution code for your reference.

but i think that my logic is also correct may be i am doing some mistake in implementation

1 Like

Yes the logic also seems to me as correct maybe due to complexity we may miss some essential observation. I could not figure the code for this logic for my own during contest and even now it feels a little complicated to think of.

The editorial solution does helps visualize the solution in a better way. But yes this logic seems to work🤔 only we need to figure out to code it in a simple way.

Can you elaborate a little more on why to focus on the odd indexes? I’m having a bad time understanding.

You can have this string:

00 10 01 11

To become it good, you could make only two changes: indexes 3,5 (1-based) or 4,6.

If 3,5 are changed, the string would be 00 00 11 11
If 4,6 are changed, the string would be 00 11 00 11

The alternating substring of 3,5 is 10
The alternating substring of 4,6 is 01

How is useful to identify exclusively the indexes different from S[0] and also odds? I guess you could detect the index 3, but not the 5th, and as I understood, the 4th neither. Not to mention, guaranteeing the alternating part.

Nevermind, I kinda understood from @joy2022 elaboration.

I guess, it’s a little overthought, specially because it has to handle many even,odds modification. Plus guaranteeing the alternanting substring might be a little too hard.

I think it’s a little more natural. If there are pairs of similar numbers “11” or “00”, just ignore them. Focus exclusively in the differents.

01 01 10 10 01

Since both are always a combination of 0 and 1, just take alternantingly 0s and 1s.
1,4,6,7,9 or 2,3,5,8,10 for that case.

1 Like

yeah I agree @ulisesaugusto1 , it feels overly complicated to find for all patterns of form OOOO...(even number of times) , OEEE....O and EEE....(provided any 1 boundary has no odd length sets i.e. OOOO EEE........ is applicable as sets are [OOOO][EEE...] but not OOOEEE... since this can be seen as [OO][OEEE....]).

Such cases will need to be checked and then all possible patterns need to be stored. Then assume the first element we want to change had been 1 then in subsequent pattern we need to make sure we somehow select a 0 which is always possible but then we need fetch index of that needed 0 accordingly.

All these tasks together make it prone to mistakes in implementation and make the simple logic overly complicated. I was stuck in implementation of this logic.