题目
思路
2n的操作是,对b数组从后往前遍历,如果当前位置与a匹配,继续下一个,如果不匹配,看a第一个元素是否匹配,如果不相同,直接对当前位置的前缀做操作,如果相同,则对a的第一个元素做一次操作,然后再对当前位置的前缀做操作。这样能保证在2n内完成。
不过t<=1e3 n <=1e5,对执行操作的区间进行线性更新会TLE。
所以找一个更快的维护方式。
记录当前区间L R,flag标记当前方向是正还是反。
从后往前跑一遍b数组,不断更新L R,记录信息即可。
这里代码写麻烦了,实际可以记录对区间操作了多少次,然后根据次数的奇偶性知道某个区间上的元素是否与原来相同,然后每次只需要直接更新,并交换L R即可,而不用讨论方向的正反。
代码
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int maxn = 1e5 + 10;
char s1[maxn], s2[maxn];
int main(){
int t; scanf("%d", &t);
while(t--){
queue<int>que;
int n; scanf("%d", &n);
scanf("%s", s1 + 1);
scanf("%s", s2 + 1);
int cnt = 0, times = 0;//取反了多少次 区间取反个数
bool flag = true; //true表示正,从右到左
int L = 1, R = n;
for(int i = n; i >= 1; i--){
if(flag){//从右到左
if(s2[i] == s1[R]){//当前位置与s1串匹配
R--;
continue;
}
if(s2[i] == s1[L]){//当前位置与头位置的相同
que.push(1);
}
que.push(i);
L++;
flag ^= 1;
}else{//从左到右
if(s2[i] != s1[L]){//当前位置与s1串匹配
L++;
continue;
}
if(s2[i] != s1[R]){//当前位置与头位置的相同
que.push(1);
}
que.push(i);
R--;
flag ^= 1;
}
}
printf("%d ", que.size());
while(!que.empty()){
int x = que.front();
que.pop();
printf("%d ", x);
}
puts("");
}
return 0;
}