仔细分析我们可以发现, s s s 和 t t t 相同的地方不需要考虑。我们只需要分别记录下不同的地方中, s s s 为 1 的位置 s i d sid sid 以及 t t t 为 1 的位置 t i d tid tid。
然后我们贪心的想,一步移动中,最多移动的次数,也就是 t i d tid tid 的左侧的不同的 s i d sid sid 的个数。每一次我们就把这些 s i d sid sid 移动到位。然后循环对剩下的 t i d tid tid 和 s i d sid sid 进行处理, a n s w e r answer answer 就是循环了多少次。
由于数据量 n = 1 e 6 n = 1e6 n=1e6,所以必须用二分查找,而且无论是查找 t i d tid tid 左侧的 s i d sid sid,还是查找下一个需要查找的 t i d tid tid,都需要二分查找。来保证时间复杂度为 n l o g n nlogn nlogn 。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6 + 5;
char s[maxn], t[maxn];
set<int> sid, tid;
set<int> ::iterator it;
queue<int> de1, de2;
bool visit[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
cin >> s >> t;
for(int i = 0 ; i < n; i++){
if(s[i] != t[i]){
if(s[i] == '1')
sid.insert(i);
else
tid.insert(i);
}
}
if(sid.size() != tid.size())
cout << -1 << endl;
else{
int cnt, ans = 0, temp;
while(!tid.empty()){
it = sid.lower_bound(*tid.begin());
while(it != sid.end()){
it = tid.lower_bound(*it);
if(it == tid.end())break;
temp = *it;
it = sid.lower_bound(temp);
it--;
if(!visit[*it]){
visit[*it] = true;
de1.push(*it);
de2.push(temp);
}
it++;
}
it = sid.lower_bound(*tid.begin());
if(it == sid.begin()){
if(!visit[*sid.rbegin()]){
de1.push(*sid.rbegin());
de2.push(*tid.begin());
}
}else{
it--;
de1.push(*it);
de2.push(*tid.begin());
}
while(!de1.empty()){
sid.erase(de1.front());
tid.erase(de2.front());
de1.pop();
de2.pop();
}
ans++;
}
cout << ans << endl;
}
}