MERGEBS - Editorial

What’s wrong with this solution?
#include <bits/stdc++.h>

#include

using namespace std;

int main()

{

int t;

cin >> t;

while (t--)

{

    int n;

    cin >> n;

    string a, b;

    cin >> a;

    cin >> b;

    int count_a_0=0,count_a_1=0;

    int count_b_0=0,count_b_1=0;

    for(int z=0;z<n;z++){

        if(a[z]=='0'){

            count_a_0++;

        }

        else{

            count_a_1++;

        }

        if(b[z]=='0'){

            count_b_0++;

        }

        else{

            count_b_1++;

        }

       

    }

    int final = 0;

    int count = 0;

    int i = 0, j = 0;

    while (i < a.length() || j < b.length())

    {

        if (i < a.length() && a[i] == '0')

        {

            final += count;

            count_a_0--;

            i++;

        }

        else if (j < b.length() && b[j] == '0')

        {

            count_b_0--;

            final += count;

            j++;

        }

        else

        {

            if(i>=a.length()){

                 count+=1;

               

                j++;

            }

            else if(j>=b.length()){

                count+=1;

                i++;

            }

            else if(count_a_0==count_b_0){

                if(count_a_1<=count_b_1){

                    count+=1;

                    count_a_1--;

                    i++;

                }

                else{

                    count_b_1--;

                    count+=1;

                    j++;

                }

            }

            else if (count_a_0>count_b_0)

            {

                count += 1;

                count_a_1--;

                i++;

            }

            else{

                count+=1;

                count_b_1--;

                j++;

            }

        }

       

    }

    cout<<final << endl;

}

}

This works for my code. Can you give any other test case?

Can anyone please give a test case where greedy approach will fail, examples given in the comment works for my code:

#include <iostream>
using namespace std;

int main() {
	// your code goes here
	int t,n;
	cin>>t;
	while(t--)
	{
	   cin>>n;
	   string s1,s2;
	   cin>>s1>>s2;
	   int c=0,z1=0,z2=0,i1=0,i2=0,j1,j2,c1,c2;
	   //cout<<"s1"<<s1;
	   //cout<<"s2"<<s2;
	   while(i1<n)
	   {
	       if(s1[i1]=='0')
	       z1++;
	       if(s2[i1]=='0')
	       z2++;
	       
	       i1++;
	   }
	   i1=0;
	   //cout<<"z1"<<z1;
	   //cout<<"z2"<<z2;
	   while(i1<n && i2<n)
	   {
	       if(s1[i1]=='1' && s2[i2]=='1')
	       {
	           if(z1>z2)
	           {
	               i1++;
	               c+=(z1+z2);
	           }
	           else  if(z1<z2)
	           {
	               i2++;
	               c+=(z1+z2);
	           }
	           else if(z1!=0)
	           {
	               
	               j1=i1+1;
	               j2=i2+1;
	               c1=s1[i1]-'0';
	               c2=s2[i2]-'0';
	               while(j1<n && c1==c2)
	               {
	                   c1+=s1[j1++]-'0';
	                   c2+=s2[j2++]-'0';
	               }
	               if(c1<c2)
	               {
	                  i1++;
	                  c+=(z1+z2); 
	               }
	               else
	               {
	                  i2++;
	                  c+=(z1+z2); 
	               }
	           }
	           else
	           {
	             break; 
	           }
	       }
	       else  if(s1[i1]=='0' && s2[i2]=='1')
	       {
	           i1++;
	           z1--;
	       }
	       else  if(s1[i1]=='1' && s2[i2]=='0')
	       {
	           i2++;
	           z2--;
	       }
	       //both 0
	       else
	       {
	           if(z1>z2)
	           {
	               i1++;
	               z1--;
	           }
	           else  if(z1<z2)
	           {
	               i2++;
	               z2--;
	           }
	          else if(z1!=0)
	           {
	               
	               j1=i1+1;
	               j2=i2+1;
	               c1=s1[i1]-'0';
	               c2=s2[i2]-'0';
	               while(j1<n && c1==c2)
	               {
	                   c1+=s1[j1++]-'0';
	                   c2+=s2[j2++]-'0';
	               }
	               if(c1<c2)
	               {
	                  i1++;
	                  z1--;
	               }
	               else
	               {
	                  i2++;
	                  z2--; 
	               }
	           }
	           else
	           {
	             break; 
	           }
	       }
	   }
	    while(i1<n)
	    {
	        if(z1==0)
	        {
	            break;
	        }
	        else
	        {
	            if(s1[i1]=='1')
	           {
	               c+=z1;
	           }
	           else
	           {
	               z1--;
	           }
	           i1++;
	        }
	    }
	    while(i2<n)
	    {
	        if(z2==0)
	        {
	            break;
	        }
	        else
	        {
	            if(s2[i2]=='1')
	           {
	               c+=z2;
	           }
	           else
	           {
	               z2--;
	           }
	           i2++;
	        }
	    }
	    
	   cout<<c<<endl;
	}
	return 0;
}

Can some one tell me the problem with just making the new string by adding as many zeroes till both strings have 1 and then adding the one which has more zeroes left after that index . etc.etc

ll n;

    cin>>n;

    string a,b;

    cin>>a>>b;

    ll aaa=stoi(a,0,2);

    ll bb=stoi(b,0,2);

   ll a0=n-__builtin_popcount(aaa);

   ll b0=n-__builtin_popcount(bb);

    ll z=a0+b0;

   

    ll i=0,j=0;

    ll aa[2*n]={0};

   

    while(i<n && j<n)

    {

       if (a[i]=='0' and b[j]=='0')

       {

           i++;

           j++;

           a0--;

           b0--;

       }

        else if (a[i]=='1' and b[j]=='1')

         {

              if (a0>b0)

              {

                  aa[i+j]=1;

                  i++;

              }

              else

              {

                  aa[i+j]=1;

                  j++;

              }

         }else if (a[i]=='0' and b[j]=='1')

         {

              a0--;

              i++;

         }else{

                b0--;

                j++;

         }

       

    }

    while(i<n)

    {

        aa[i+j]=a[i]-48;

        i++;

    }

    while(j<n)

    {

        aa[i+j]=b[j]-48;

       

        j++;

    }

    ll ans=0;

    l(i,0,2*n)

    {

        // cout<<aa[i]<<"|"<<i<<" ";

        if(aa[i]==0)

        {

            z-=1;

           

        }else{

            ans+=z;

        }

    }

    cout<<ans<<"\n";

I think the tests are weak. My O(n^3) DP solution passes. I coded this to check my logic and was hoping to optimize this using segment tree but O(n^3) passed.
Code Link: CodeChef: Practical coding for everyone

What should be the answer for this test case.
I’m getting 26 , is it correct?

Can someone plz explain me this doubt :
The editorial mentions that if we’ve merged A[1…i] and B[1…j], now we’ve to take either A[i+1] or B[j+1] but why cant we take both, I mean A[i+1] and B[j+1]

https://www.codechef.com/viewsolution/56740325 My Top Down Solution to the problem, if anybody is interested.

3 Likes

Logic : take substrings of one’s and zero’s and find the value which should be placed before since a string’s own contribution cannot be changed, all we can do is change the contribution in the of a string in the second string.

On your tc my code is giving 20.
But wa ;_;

/*    Author : Prakhar Rai    */
#include<bits/stdc++.h>
using namespace std;

typedef long long 		 ll;
typedef long double		 ld;

#define FIO         ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define ln(s)	    ll(s.length())
#define sz(a)	    ll(a.size())
#define pb          emplace_back
#define fs          first
#define sc          second
#define vcll        vector<ll>
#define all(x)      x.begin(),x.end()
#define endl        "\n"
#define vc          vector
#define FOR(i,a,b)  for(ll i = a; i < b; i++)
#define pika(x)     cerr << #x << ' ' << x << endl;
#define yes         "YES"
#define no          "NO"

const int mod = 1e9 + 7;
const int MOD = 998244353;
const int N = 2e5 + 5;



void test_case() {
	ll n, p1(0), p2(0);
	cin >> n;
	string a, b, s = "";
	cin >> a >> b;

	while (p1 < n and a[p1] == '0') p1++;
	while (p2 < n and b[p2] == '0') p2++;

	ll fa = 1, fb = 1, ans = 0; // add individual contributions
	while (p1 < n and p2 < n) {
		ll a0, a1, b0, b1, sa, ea, sb, eb;
		a0 = a1 = b0 = b1 = 0;

		sa = p1;
		while (p1 < n and a[p1] != '0') a1++, p1++;
		while (p1 < n and a[p1] != '1') a0++, p1++;
		ea = p1;

		sb = p2;
		while (p2 < n and b[p2] != '0') b1++, p2++;
		while (p2 < n and b[p2] != '1') b0++, p2++;
		eb = p2;


		// cout << "a " << sa << ' ' << ea << endl;
		// cout << "b " << sb << ' ' << eb << endl;

		// add edge case - end one's
		// cerr << a0 << ' ' << a1 << endl;
		// cerr << b0 << ' ' << b1 << endl;

		if (a1 * b0 < b1 * a0) {
			s += a.substr(sa, ea - sa);
			p2 = sb;
		} else {
			s += b.substr(sb, eb - sb);
			p1 = sa;
		}

		// cout << s << endl;
	}

	if (p1 < n) while (p1 < n) s += a[p1++];
	if (p2 < n) while (p2 < n) s += b[p2++];

	// cout << ans << endl;
	// cout << s << endl;
	// s = "101010110110";
	ll len = ln(s);
	for (int i = 0; i < len; i++) {
		if (s[i] == '1') {
			ll z = 0;
			for (int j = i + 1; j < len; j++)
				if (s[j] == '0') z++;
			ans += z;
		}
	}
	cout << s << endl;
	cout << ans << endl;
}



int main() {
	FIO;
	int _tests;
	_tests = 1;
	cin >> _tests;
	for (int i = 1; i <= _tests; i++) {
		// cout << "Case #" << i << ": ";
		test_case();
	}
}

I’m getting Runtime Error in last 3 testcases , can someone please tell me what’s the problem.
import sys

for _ in range(int(input())):

    def rec(i, j, zeros, memo={}):

        if (i, j) in memo:
            return memo[(i, j)]

        if i >= n:
            x = s2[j:].count('0')
            count = 0
            for k in range(j, n):
                if s2[k] == '0':
                    x -= 1
                else:
                    count += x
            return count
        if j >= n:
            x = s1[i:].count('0')
            count = 0
            for k in range(i, n):
                if s1[k] == '0':
                    x -= 1
                else:
                    count += x
            return count

        else:
            if s1[i] == "1" and s2[j] == "1":
                memo[(i, j)] = zeros + min(rec(i + 1, j, zeros), rec(i, j + 1, zeros))
                return memo[(i, j)]
            elif s1[i] == "0" and s2[j] == "0":
                memo[(i, j)] = min(rec(i + 1, j, zeros - 1), rec(i, j + 1, zeros - 1))
                return memo[(i, j)]
            else:
                if s1[i] == "0":
                    memo[(i, j)] = min(rec(i + 1, j, zeros - 1), zeros + rec(i,j+1,zeros))
                    return memo[(i, j)]
                elif s2[j] == "0":
                    memo[(i, j)] = min(rec(i, j + 1, zeros - 1), zeros + rec(i+1,j,zeros))
                    return memo[(i, j)]


n = int(input())
s1 = sys.stdin.readline()
s2 = sys.stdin.readline()
z = s1.count('0') + s2.count('0')
print(rec(0, 0, z))

Can Anybody Tell Me in Which testcase This code will fail?
Is this code right or not?
Bottom Up DP Solution.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[1001][1001];
int solve(string a,string b,string c,int i,int j)
{
    // cout<<i<<" "<<j<<"\n";
    if(i==a.size() or j == b.size())
    {
        //count inversion and return that
        if(i==a.size())
        {
            c+=b.substr(j);
        }
        else if(j == b.size())
        {
            c+=a.substr(i);
        }
        // cout<<c<<"\n";
        int ans = 0;
        for(int i=0;i<c.size();i++)
        {
            if(c[i]=='0') continue;
            int cnt = 0;
            for(int j = i+1;j<c.size();j++)
            {
                if(c[j]=='0')
                {
                    cnt++;
                }
            }
            ans+=cnt;
        }
        return  dp[i][j] =  ans;
    }
    if(dp[i][j]!=-1)
    {
        return dp[i][j];
    }
    if(a[i] == b[j])
    {
        int op1 = solve(a,b,c+a[i],i+1,j);
        int op2 = solve(a,b,c+b[j],i,j+1);
        return dp[i][j] = min(op1,op2);
    }
    else
    {
        if(a[i]=='0')
        {
            return  dp[i][j] =  solve(a,b,c+a[i],i+1,j);
        }
        if(b[j]=='0')
        {
            return  dp[i][j] =  solve(a,b,c + b[j], i ,j+1);
        }
    }
    return  dp[i][j] =  0;
}
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    ll t;
    cin>>t;
   
    while(t--)
    {
        memset(dp,-1,sizeof(dp));
        int n;
        cin>>n;
        string a,b;
        cin>>a>>b;
        string c;
        cout<<solve(a,b,c,0,0)<<"\n";
    }
    return 0;
}

8
00101010
10111010
Ans is 25

See my post above, it gives 25 too!

I think, runtime error seems to be caused due to maximum recursion depth getting exceeded.
For fixing this just add the following line after importing the sys module.

sys.setrecursionlimit(10 ** 6)

For more info, you can refer this

Thanks man it did worked.
That’s why i love this community.

can you give the resultant string
mine is
0010111010101010
and answer comes 31.

my resultant string for the above case formed is 110000101010
and answer = 20.
can you provide the resulting string?

My greedy solution works on the test cases given in comments. I calculated which ‘1’ brings how many inversions for both strings, then greedily added the ‘1’ with higher inversions to my answer string. I calculated the total inversions in the answer string and i dont recognize the flaw. Can anyone please point it out.

Solution Link: CodeChef: Practical coding for everyone

Check this testcase:
1
9
010010110
001101100
Answer: 28
Your code’s output: 29

1
9
010010110
001101100