大致题意
如果一个字符串形如 010101010... 010101010... 010101010... 或 10101010... 10101010... 10101010...,则该字符串为不稳定字符串。字符串中只含有 1 , 0 , ? 1, 0, ? 1,0,?,其中 ? ? ?可以看作 1 1 1或 0 0 0。求字符串的子串(连续)中有多少不稳定字符串。
Input
3
0?10
???
?10??1100
Output
8
6
25
一道经典的算法题,考虑如何去减少复杂度,一步步让算法变得更加高效。
以此题为例,讲一下作为一个OIer应该如何去思考问题。
首先注意到,字符串只有 1 , 0 , ? 1,0,? 1,0,?三种类型,而 ? ? ?可作为特殊的两用存在,故在不考虑问号存在的情况下考虑如何计数。
无问号
选择最为朴素的做法,三个循环,前两个为两下标i和j,第三个循环计算以 i i i开头以 j j j收尾的子字符串是否稳定。很明显时间复杂度为 O ( n 3 ) O(n^3) O(n3),简单但时间无法承受。
考虑优化,因为是连续字串,且发现一个不稳定字符串的连续子串一定不稳定(传递性),因此无需重复计算,稍微思考则可认定使用扫描法计算数目。
运用扫描法我们便可得到一个子串集:他们互不相连,并且无法找到长度总和比他们更长的字符串。且时间复杂度为 O ( n ) O(n) O(n),可以通过。
每一次扫描到一个位置时,可以判断其是否与上一个位置不同,若是则 v a l u e + 1 value+1 value+1,否则 v a l u e value value清除为 1 1 1.每一次扫描都需要加上这一次的 v a l u e value value值,得到结果。
有问号
考虑问号对字符串的影响,可以发现,
如果问号是连续的,则无需考虑其影响,这一个子字符串一定不稳定。且可以发现,如果该子串与另一个不稳定子串相邻,那么它们组合便可以得到一个更加长的不稳定子串。现在我们得到了以下的结论:
- A substring of the unstable string is an unstable string.
- If a string is all ‘?’, then another unstable string combined with it is unstable.
现在我们就能够思考这一种情形了:
如: “010101?????0101”
1和2可以组成不稳定子串,2和3可以组成不稳定子串,但1,2和3不能组成,原因是不论?替换成1或0,都不能使其排成0101的形式。
当扫描到3时,我们需要放弃1结束时的 v a l u e value value值,考虑如此,我们需要独特的计数方法,这里我们应用一个 m a r k mark mark值,记录出现连续的 ? ? ?的个数,当连续的 ? ? ?结束后,我们需要判断这一个子串3是否与前前一个子串1连接。
这里选择将?进行替换,替换的内容依据前一子串1而定。让1和2能够成为一个不稳定子串。此时3能否与1和2联系便可直接从被替换的2出发。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while(T-- > 0) {
string s;
cin>>s;
long long mark = 0, v = 0, ans = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] != '?') {
if(s[i] == s[i-1]) v = mark;
mark = 0;
}else {
s[i] = s[i-1] == '1' ? '0' : '1';
mark++;
}
v++;
ans += v;
}
printf("%lld\n", ans);
}
}
对了,数据范围大,记得写LL。
其他练习题:
同样是一道只含“0,1,?”的字符串,但涉及了一些修改,查询的操作。思路和树有关
1536B Prinzessin der Verurteilung
一道有关字典序的暴力题。思路很有趣,博主暂时只想到了进制转换和BFS的思路,欢迎私信讨论。