本蒟蒻坚持每日一题保持手感的一天… 题目链接
题目分析
本题如果拥有强大的逻辑推理能力,推出题目的各种隐藏条件和性质,还是可以做的非常优雅的,可惜本蒟蒻没有。
回归正题,对于题目的更改规则具有以下性质:
性质
- 无法同时改变相邻的1或0(即11或00)。
- 每个修改具有不可逆性。
- 修改次数与修改顺序无关。
- 根据性质三可得可以从左向右遍历字符串。
- 由性质2可得字符串匹配的数字一定不能改,且由于性质4,从左到右只遍历一次,遇到不匹配的字符一定要修改。
性质推导
性质1
当相邻两个相同字符都需要更改时,每个字符更改的前提是,相邻字符不相同,但此时至少相邻字符是一致的,需求与条件矛盾,故无法实现该需求。
简单来说,两个字符都在等待对方发生变化,故无法同时进行变化。
性质2
第一次改变:
尝试回归…
最后…
回到了性质一的死锁。
性质三
由性质2可得,初始字符匹配时一定不能更改,则只需要修改需要修改的部分,而需要修改的条件题目已经指定了,相邻字符要不同,所以先修改哪一个其实是不影响结果的,只是先后问题,题目求的是次数,无需统计先后。
性质4,5都是根据以上三条性质推出,在此不做赘述。
总结:从左向右遍历,遇到不匹配的需要更改,而可以更改的条件是左右两边跟当前字符不匹配,当可以更改时,对更改次数+1,不能更改时,直接输出-1。
AC码
PS:话多提一嘴,我用sizeof
算字符串长度最后一个测试点超时,改成strlen
就过了,离谱…
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
char s[N], t[N];
int main() {
int d;
scanf("%d", &d);
while(d --) {
scanf("%s%s", t, s);
int l = strlen(s);
int cnt = 0;
for(int i = 0; i < l; i ++) {
if(s[i] != t[i]) {
if(!i || i == l - 1 || s[i] == s[i - 1] || s[i] == s[i + 1]) {
cnt = -1;
break;
}
cnt ++;
s[i] = t[i];
}
}
printf("%d\n", cnt);
}
return 0;
}