题目大意:
给出a、b两个由0和1组成的字符串
现在你可以选择一段0和1数量相等的前缀,将其所有0换成1,所有1换成0
你可以操作无数次
你只需要判断a能否经过若干次操作变成b
思路
这题我一开始是想直接模拟的,就是从后往前遍历a,遇到a[i]!=b[i]时,若可以反转,就反转一次,否则直接输出NO,写到一半发觉复杂度不对劲…
Ctrl+A+Backspace删代码可真爽…
正解:
用数组c记录字符串a各位置0和1的相对数量
(例如c[i]==-1表示:从开头到下标i的这段前缀0比1多一个)
然后还是从后往前走,用变量rtime记录反转次数,反转次数为奇数就说明a[i]被转了
而为偶数则不用理睬,用变量tmp表示此时a[i]的真实值。
如果tmp==b[i],continue就好了。else if 此时不能反转,直接输出NO
否则就当成是反转一次,rtime++
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int N=3e5+7;
int c[N];
int n;
void solve(){
string a,b;
cin>>n>>a>>b;
if(a[0]=='0') c[0]=-1;
else c[0]=1;
for(int i=1;i<n;i++){
if(a[i]=='0') c[i]=c[i-1]-1;
else c[i]=c[i-1]+1;
}
int rtime=0,cnt=0;
for(int i=n-1;i>=0;i--){
char tmp=a[i];
if(rtime&1){
if(tmp=='0')tmp='1';
else tmp='0';
}
if(rtime&1)cnt=-c[i];
else cnt=c[i];
if(tmp==b[i]) continue;
if(cnt){
//cout<<"info: "<<cnt<<' '<<i<<' '<<rtime<<'\n';
cout<<"NO"<<'\n';
return;
}
rtime++;
}
cout<<"YES"<<'\n';
}
int main(){
int t;
cin>>t;
while(t--)solve();
return 0;
}
其实好像不需要开数组c也能做,懒得改了233 能过就行。