C - Menorah

两个01串s1和s2。求最少的操作数把s1变为s2,不能则为-1

操作:固定一个1,其余位全部取反

我们的目标是让所有的位置变得相同。

考虑两个字符串相同的0**(00)和1(11)的数量,以及不同的0(01)和1(10)**的数量。

一个位置点两次是没有意义的,而连续点两个位置相当于交换了两个位置。(1和0)

所以对于当前不同的,即01,10:我们有两种策略:

  • 点不同的位置。如果不同的位置的1和0数量相等,即可全部交换。因为点了偶数次所以对初始相等的不造成影响
  • 点相同的位置。相同的位置点奇数次,即可让不同的位置变成相同,那么问题转换成了如何点奇数次使得相同的位置不变。
    • 我们只需要让1的数量比0的数量多1,即可在偶数次交换01后使有一个11,而其他的全部不同。
#include <bits/stdc++.h>
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
/**/
const int N = 1e5 + 5;
int t, n, sc1, sc0, dc1, dc0;
char s1[N], s2[N];
/**/
int main()
{
	read(t);
	while(t--)
	{
		read(n);
		scanf("%s%s", s1 + 1, s2 + 1);
		sc1 = sc0 = dc1 = dc0 = 0;
		for(int i = 1; i <= n; i++)
		{
			if(s1[i] == s2[i])
			{
				if(s1[i] == '1') sc1++;
				else sc0++;
			}
			else
			{
				if(s1[i] == '1') dc1++;
				else dc0++;
			}
		}
		int ans = 0x3f3f3f3f;
		if(dc0 == dc1) ans = min(ans, dc0 + dc1);
		if(sc1 == sc0 + 1) ans = min(ans, sc1 + sc0);
		if(ans == 0x3f3f3f3f) cout << -1 << '\n';
		else cout << ans << '\n';
	}
	return 0;
}