本文已参与「新人创作礼」活动,一起开启掘金创作之路。
样例输入:
5
1
1
2
01
3
100
4
1001
5
11111
样例输出:
1
3
4
8
5
题意:多组测试,每次给定一个n,代表字符串的长度,然后给定一个长度为n的字符串,字符串中的每个字符为0或者1,我们可以对一个字符串进行操作,每次可以把01变成1或者把10变成0,然后问我们在这个字符串中有多少个子串可以经过若干次操作变为一个数。
举个例子比如100,首先1,0,0三个单独可以作为一个子串,其次100整体可以作为一个子串,因为100->10->0,所以对于100共有4个子串可以经过若干次操作变为一个数,而对于1001的话就有
1,0,0,1,10,01,001,1001这8个子串满足题意
这个题有两种做法,先来说一下比较简单的做法:
假如第i个数字与第i-1个数字不同,那么我们直接把答案+i就行,因为以第i个数字结尾向前扩展任意长度的子串都是满足题意的,为什么会这样呢?给大家举个例子大家应该就明白了:
比如序列是xxxxxxxxxxxx01,我们可以通过若干次操作把前面的x全部变成0,因为假如前面是0那就不用操作,如果前面是1,那我们可以用倒数第二个数0和前面的数组成10然后合成0重复这样的操作就可以使得所有的x变为0,那么就成为了00……01的这种形式,然后就可以直接合并成1
同理假如序列是xxxxxxxxxxxx10,我们可以通过若干次操作把前面的x全部变成1,因为假如前面是1那就不用操作,如果前面是0,那我们可以用倒数第二个数1和前面的数组成01然后合成1重复这样的操作就可以使得所有的x变为1,那么就成为了11……10的这种形式,然后就可以直接合并成0
如果要是当前位和上一位是相同的,因为01->1,10->0所以我们无论怎样操作最后都无法消成一个数,所以只需要把答案+1即可,因为只有把当前这一个字符作为子串才是满足题意的。
代码实现很简单,注意ans开long long:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
const int N=2e5+10;
char s[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d%s",&n,s+1);
long long ans=1;
for(int i=2;i<=n;i++)
{
if((s[i]-'0')^(s[i-1]-'0')) ans+=i;
else ans+=1;
}
printf("%lld\n",ans);
}
return 0;
}