【题解】StarryCoding P235 再短一点

题目传送门:P235 再短一点 | StarryCoding算法竞赛平台

题目描述

当一个长度为 m m m的二进制字符串 T T T是幸运的,我们可以通过任意顺序执行以下两种操作 m − 1 m-1 m1来获得长度为 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 1lrn)使得 S [ l … r ] S[l \ldots r] S[lr]( S S S l l l r r r的子字符串)是一个幸运的字符串的整数对的个数。

输入描述

第一行包含一个整数 t t t( 1 ≤ t ≤ 1000 1 \le t \le 1000 1t1000)—测试用例的数量。下面是测试用例的描述。

每个测试用例的第一行包含一个整数 n n n( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1n2105)——大小为 S S S

每个测试用例的第二行包含一个由 n n n字符 S 1 S 2 … S n S_1S_2 \ldots S_n S1S2Sn组成的二进制字符串 S S S。(每个 1 ≤ i ≤ n 1 \le i \le n 1in对应 S i = S_i = Si= 0或 S i = S_i = Si= 1)

保证所有测试用例的 n n n之和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2105

输出描述

对于每个测试用例,输出使 S [ l … r ] S[l \ldots r] S[lr]( 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)1lrn的个数。

输入样例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[m1])。

  • S [ m − 1 ] = S [ m ] S[m - 1] = S[m] S[m1]=S[m]的情况下:我们永远不能删除最后两个字符,因为它们将始终保持相等。所以 S S S 不是幸运的。
  • S [ m − 1 ] ≠ S [ m ] S[m - 1] \neq S[m] S[m1]=S[m]的情况下:如果 m = 2 m = 2 m=2,我们可以通过一次操作达到我们的目标。否则,假设最后一个字符为0。现在最后三个字符不是010就是110。在第一种情况下,对 [ S m − 2 , S m − 1 ] [S_{m-2},S_{m-1}] [Sm2,Sm1]执行操作,在第二种情况下,对 [ S m − 1 , S m ] [S_{m-1},S_m] [Sm1,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[r1]成立,我们应该在答案上加上 r − 1 r - 1 r1

复杂性: 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改编而成

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值