题目传送门:P235 再短一点 | StarryCoding算法竞赛平台
题目描述
当一个长度为 m m m的二进制字符串 T T T是幸运的,我们可以通过任意顺序执行以下两种操作 m − 1 m-1 m−1来获得长度为 1 1 1的字符串:
-
选择 T T T中任意等于01的子字符串,将其替换为1。
-
选择 T T T中任何等于10的子字符串,然后将其替换为0。
例如,如果 T = 001 T = 001 T=001,我们可以选择子字符串 [ T 2 T 3 ] [T_2T_3] [T2T3]并执行第一个操作。得到 T = 01 T = 01 T=01。
您将得到一个长度为 n n n的二进制字符串 S S S,索引从 1 1 1到 n n n。找出 ( l , r ) (l, r) (l,r)( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1≤l≤r≤n)使得 S [ l … r ] S[l \ldots r] S[l…r]( S S S从 l l l到 r r r的子字符串)是一个幸运的字符串的整数对的个数。
输入描述
第一行包含一个整数 t t t( 1 ≤ t ≤ 1000 1 \le t \le 1000 1≤t≤1000)—测试用例的数量。下面是测试用例的描述。
每个测试用例的第一行包含一个整数 n n n( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105)——大小为 S S S。
每个测试用例的第二行包含一个由 n n n字符 S 1 S 2 … S n S_1S_2 \ldots S_n S1S2…Sn组成的二进制字符串 S S S。(每个 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n对应 S i = S_i = Si= 0或 S i = S_i = Si= 1)
保证所有测试用例的 n n n之和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
输出描述
对于每个测试用例,输出使 S [ l … r ] S[l \ldots r] S[l…r]( S S S从 l l l到 r r r的子字符串)为偏执字符串的整数对 ( l , r ) 1 ≤ l ≤ r ≤ n (l, r)1 \le l \le r \le n (l,r)1≤l≤r≤n的个数。
输入样例1
5
1
1
2
01
3
100
4
1001
5
11111
输出样例1
1
3
4
8
5
样例解释
在第一个示例中, S S S已经具有长度 1 1 1,不需要任何操作。
在第二个示例中, S S S的所有子字符串都是幸运的。对于整个字符串,执行第一个操作就足够了。
在第三个示例中,除了 [ S 2 S 3 ] [S_2S_3] [S2S3]之外, S S S的所有子字符串都是幸运的,因为我们不能对它和 [ S 1 S 2 S 3 ] [S_1S_2S_3] [S1S2S3](整个字符串)执行任何操作。
思路
长度为 m m m的二进制字符串 T T T是幸运的,当且仅当 m = 1 m = 1 m=1或( 1 < m 1 \lt m 1<m和 S [ m ] ≠ S [ m − 1 ] S[m] \neq S[m - 1] S[m]=S[m−1])。
- 在 S [ m − 1 ] = S [ m ] S[m - 1] = S[m] S[m−1]=S[m]的情况下:我们永远不能删除最后两个字符,因为它们将始终保持相等。所以 S S S 不是幸运的。
- 在 S [ m − 1 ] ≠ S [ m ] S[m - 1] \neq S[m] S[m−1]=S[m]的情况下:如果 m = 2 m = 2 m=2,我们可以通过一次操作达到我们的目标。否则,假设最后一个字符为0。现在最后三个字符不是010就是110。在第一种情况下,对 [ S m − 2 , S m − 1 ] [S_{m-2},S_{m-1}] [Sm−2,Sm−1]执行操作,在第二种情况下,对 [ S m − 1 , S m ] [S_{m-1},S_m] [Sm−1,Sm] 执行操作。然后最后两个字符将是10,我们可以在新的字符串上继续这个算法,直到我们得到 m = 1 m = 1 m=1。
长度为 1 1 1的幸运的子字符串的个数等于 n n n。为了计算更长的子字符串的个数,我们可以将索引 2 2 2中的 r r r固定为 n n n。如果 S [ r ] ≠ S [ r − 1 ] S[r] \neq S[r - 1] S[r]=S[r−1]成立,我们应该在答案上加上 r − 1 r - 1 r−1。
复杂性: O ( n ) \mathcal{O}(n) O(n)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
void solve()
{
int n; cin >> n;
ll ans = n;
string s; cin >> s;
for(int i = 1; i < n; ++i)
{
if(s[i] != s[i - 1]) ans += i;
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while(_ --)solve();
return 0;
}
本题由codeforces上的1694B改编而成