Codeforces Round #807 (Div. 2) D
传送门: Mark and Lightbulbs
题意: 对于一个 01 字符串,如果与某个比特位相邻的两个比特不相等,就可以翻转该比特位,即如果 s[i-1] != s[i+1] 就可以翻转 s[i]。现给定两个 01 字符串 s 和 t,问 s 能否转化为 t,最少操作数是多少。
思路:
如果将连续的 0 或 1 视为一整个块(以下称为 01 块),原字符串就可以视为 01 块交替出现的序列。根据题意可知,只有相邻的两个块的边界处的两位比特位可以翻转,同时,如果某个块内只有一位数,那么这个数就不能被翻转,所以无论如何操作,翻转后 01 块的数量不会改变。
所以,如果两个字符串的01块序列不相等,就无法相互转化,反之就一定可以相互转化,这样我们可以轻松地判断两个字符串能否相互转化,但是直接模拟求转化步骤数仍然不方便。
进一步考虑,如果已知两个字符串 01 块序列相同,我们现在需要将两个 01 块序列对应的块的大小调整为一致。这时可以从块的边界入手,将各个块的大小对齐相当于将块的边界对齐。显然,对齐一对边界的最小操作数为两边界位置之差,所以我们只需找出两个 01 字符串中所有边界的位置,通过边界的数量可以判断 01 块数量是否相同,进而判断 01 块序列是否相同,而各对应边界的位置之差的总和则为转化字符串所需的操作数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fsio ios::sync_with_stdio(false)
const int maxn = 2e5+10;
char s[maxn], t[maxn];
int main()
{
fsio;
int T;
cin>>T;
while(T--)
{
int n;
vector<int> a, b;
cin>>n; cin>>s; cin>>t;
for (int i = 1; i < n; i++)
{
if (s[i] != s[i-1]) a.push_back(i);
if (t[i] != t[i-1]) b.push_back(i);
}
if (s[0] != t[0] || a.size() != b.size()) cout<<-1<<endl;
else
{
ll ans = 0;
for (int i = 0; i < (int)a.size(); i++) ans += abs(a[i] - b[i]);
cout<<ans<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号