BILM - Editorial

PROBLEM LINK:

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

Author: pols_agyi_pols
Tester: tabr
Editorialist: iceknight1093

DIFFICULTY:

TBD

PREREQUISITES:

None

PROBLEM:

Given a binary string S, you can perform the following types of operations on it:

  • Delete any character from S; or
  • Choose an index i and flip S_i, i.e, convert it to 0 from 1 and vice versa.

Find the lexicographically minimum possible final string S if you can perform at most K operations.

EXPLANATION:

First, we must decide how many moves we should perform; since we can make at most K.
It’s not hard to see that it is, in fact, optimal to always make K moves.

Why?

Suppose we make strictly less than K moves, and obtain the string A as a result.

Since there’s at least one move remaining, we can use one move to delete the last character of A to obtain a string that’s lexicographically smaller than A; so using less than K moves is never optimal.


Now that we know we’re going to make K moves, we need to decide what to do with them.

It can be observed that:

  • If S has more than K ones, it’s not possible to remove all the ones from S (since each move can remove at most one of them).
    In this case, the best thing we can do is convert the first K ones of S into zeros.
  • If S has \leq K ones, it’s possible to remove all of them (either via deletion or by turning them into zeros); and end up with a string consisting of only zeros.
    When a string has only zeros, it’ll be lexicographically minimum when it’s as short as possible.
    Clearly, the shortest possible string we can attain is just N-K zeros (by using one deletion move each time); and so this is the answer.

tl;dr:

  • If S contains \geq K ones, convert the first K of them to zeros.
  • If S contains \lt K ones, the answer is N-K zeros.

TIME COMPLEXITY:

\mathcal{O}(N) per testcase.

CODE:

Author's code (C++)
#include <bits/stdc++.h>
using namespace std;
#define ll long long

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
    ll kitne_cases_hain;
    //freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
    cin>>kitne_cases_hain;
    assert(1<=kitne_cases_hain && kitne_cases_hain<=1e5);
    ll sum=0;
    while(kitne_cases_hain--){     
        ll n,k;
        cin>>n>>k;
        assert(1<=n && n<=2e5);
        assert(0<=k && k<n);
        sum+=n;
        string s;
        cin>>s;
        assert(s.size()==n);
        ll cnt=0;
        for(int i=0;i<n;i++){
            assert(s[i]=='0' || s[i]=='1');
          if(s[i]=='1'){
            cnt++;
          }
        }
        if(cnt<=k){
          for(int i=0;i<n-k;i++){
            cout<<"0";
          }
          cout<<"\n";
        }else{
          for(int i=0;i<n;i++){
            if(k==0){
              break;
            }
            if(s[i]=='1'){
              k--;
              s[i]='0';
            }
          }
          cout<<s<<"\n";
        }
    }
    assert(sum<=2e5);
	return 0;
}
Editorialist's code (Python)
for _ in range(int(input())):
    n, k = map(int,  input().split())
    s = list(input())
    o = s.count('1')
    if k >= o: print('0'*(n-k))
    else:
        for i in range(n):
            if s[i] == '1' and k > 0:
                s[i] = '0'
                k -= 1
        print(''.join(s))
1 Like

@iceknight1093 @pols_agyi_pols
In the question “BILM,” it wasn’t explicitly stated that we could perform any one of the given operations. The absence of “or” makes it challenging for a Div 4 or Div 3 or even higher Div participant to conclude this solution. In my view, this omission adds confusion and increases the likelihood of misinterpretation in many instances.

I’m adding the screenshot of the question for the ref.

according to question lexicographically smallest can be x if x prefix y or xi < yi. If we consider this then the answer wont be n-k zeroes as this is not prefix.

Actually answer according to given lexicographically smallest definition given wrong.
this question answer should be reconsider.

2 Likes