Problem:
F： 01 文字列と窓 (Binary String with Slit)

問題

文字の種類が 0 と 1 のみからなる文字列 S が与えられます。以下の操作を繰り返すことで、S を T に変えたいです。

文字列 S 中の最も右側に登場する 1 を含むように、幅 2 のスリットを置く。スリット内には連続した 2 文字を必ず含まなければならない。つまり、文字列の端 1 文字のみを含むように置くことはできない。2 通り置ける場合も考えられるが、この場合はどちらの方法で置いても構わない。

スリット中の 2 文字を 2 桁の二進数と捉えるとき、元の数値との差の絶対値が 1 になるようにスリット中の文字を変更する。ただし、スリット中の文字の両方が 0 になってはならない。つまり、変更後のスリット内の数値は 1 から 3 までのいずれかとなる。

クエリが Q 回与えられます。i 番目のクエリで 1 を少なくとも一つ含む文字列 S_i, T_i が与えられるので、S_i を T_i に変えるために必要な操作回数の最小値を、それぞれのクエリについて求めてください。

入力形式

Q
S_1 T_1
...
S_Q T_Q

1 行目では、クエリの個数 Q が与えられる。

2 行目以降 Q 行は、クエリが与えられる。 i+1 行目では S_i と T_i が空白区切りで与えられる。

制約

1 \leq Q \leq 10^5

2 \leq |S_i| = |T_i| \leq 50

S_i, T_i は 0 と 1 のみからなる文字列である。

S_i, T_i はともに 1 を少なくとも 1 つ含む文字列である。

出力形式

出力は Q 行からなる。

i 行目には、i 番目のクエリに対する結果を出力せよ。

入力例1

4
101 110
101 101
1010 1101
11011001 10010101

出力例1

1
0
3
12

1 個目のクエリでは、S = 101 を T = 110 と一致させるために必要な操作回数の最小値を求める必要があります。以下の画像のように、 S の中に登場する 1 の中で最も右にあるものが含まれるようにスリットを置き、スリット中の文字列を書き換えることで 1 回の操作で S と T を一致させることができます。

2 個目のクエリでは、はじめから S と T が一致しているため、操作の必要がありません。

3 個目のクエリについて、以下の画像のように文字列を変更させると 3 回の操作で S と T を一致させることができます。

Solution in C++ (judge verdict: Accepted)

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


typedef long long ll;
#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)

char s[52], t[52];
int lsb(ll x){
  int r = 0;
  while(true){
    if((x>>r)&1)return r;
    r++;
  }
}
int erhe(ll s, ll t){
  int r = 50;
  while(true){
    if(((s>>r)&1) != ((t>>r)&1))return r;
    r--;
  }
}
int erlw(ll s, ll t){
  int r = 0;
  while(true){
    if(((s>>r)&1) != ((t>>r)&1))return r;
    r++;
  }
}
int sub(ll a, ll b){
  int ans = 0;
  while(a!=b){
    int x = lsb(a);
    int e = erhe(a,b);
    int f = erlw(a,b);
    ans++;
    // printf("(%lld, %lld): x(%d),e(%d),f(%d)\n",a,b,x,e,f);
    if(x<e || x==f){
      a = a & ~(1ll<<x);    // reset x
      a = a | (1ll<<(x+1)); // set x+1
    }else{
      a = a ^ ((a^b) & (1ll<<x));
      a = a | (1ll<<(x-1)); // set x-1
    }
    if(ans>2521)return 2521;
  }
  return ans;
}
void solve(){
  REP(i,52)s[i]=t[i]='\0';
  scanf("%s%s",s,t);
  int n = strlen(s);
  ll a=0, b=0;
  REP(i,n){
    a<<=1; a+=s[i]-'0';
    b<<=1; b+=t[i]-'0';
  }
  printf("%d\n",sub(a,b));
}

int main(){
  // sub(18,16);
  // return 0;
  // // if(true){
  // //   while(true){
  // //     ll a = rand() % 64;
  // //     ll b = rand() % 64;
  // //     if(a==0 || b==0)continue;
  // //     if(sub(a,b) == 2521){
  // //       printf("%lld %lld\n",a,b);
  // //       return 0;
  // //     }
  // //   }
  // // }
  int q;
  scanf("%d",&q);
  while(q--)solve();
  return 0;
}

// s, x = lsb(s)
// a = (s>>(x+1))&1
// if(x>0)  s-(1<<(x-1)) is ok
// if(x>0)  s+(1<<(x-1)) is ok
// if(a==1) s-(1<<x) is ok
// if(a==0) s+(1<<x) is ok

// x is lsb position
// if x>0 then reset(x) & set(x-1) & x++
// if x>0 then            set(x-1)
// if s[x-1]==1 then reset(x)            & x--
// if s[x-1]==0 then reset(x) & set(x-1) & x--

//    x+1 x+0 x-1
//      ?   1   0
// a.   ?   0   1   x--
// b.   ?   1   1   x--
// c.   1   0   0   x++