单点时限: 1.0 sec
内存限制: 128 MB
定义一个字符串s是一步字符串
,当 s 满足以下两个条件:
- s 中仅包含小写字母。
- 对于任意的1≤i<|s|满足,s[i]+1=s[i+1],也就是说,s[i]在英文字母表中的位置的下一位是s[i+1],特别的,我们认为z的下一位是a,其中|s|表示s的长度。
举个例子:abc、zab 都是一步字符串
,而 acd、zbc不是。
Steve 特别喜欢长长的名字,因此他在 Minecraft 中的名字特别特别的长。
Alex 对 Steve 的名字特别感兴趣,她想知道 Steve 的名字中有多少个子串是一步字符串
。
形式化来说,对于一个字符串 s,问有多少对 <i,j> 满足 1≤i≤j≤n,且 s[i]...s[j] 是一步字符串
。
保证 Steve 在 Minecraft 中的名字仅包含小写英文字母。
输入格式
输入包含多组测试数据。
第一行一个数字 T ,表示测试数据个数。
接下来每两行表示一个测试数据。
第一行一个数字 n 。
第二行一个长度为 n 的字符串 s。
数据范围:1≤T≤100,1≤n≤2⋅10^5
输出格式
一个数字表示答案。
样例
input
2 3 abc 3 zab
output
6 6
提示
abc
中的一步字符串有a
、b
、c
、ab
、bc
、abc
。zab
中的一步字符串有z
、a
、b
、za
、ab
、zab
。
题解:
题目分析:题意很容易就能理解,关键是如何计算子串的个数。
来看数据范围,抛去100组测试数据不说,你光是2*10^5暴力枚举两次,就爆了。
那么,换个角度去看问题吧。这道题其实是个思维题,也要找到规律。即使允许暴力,找到规律的做法也更为简洁,看来思维真是比懂的算法多重要啊。
首先分析样例,通过样例可以知道,a、b、c,单个任意字母为一个子串,两个、三个字母都可以成为子串,那4个也能成为子串了。像这样3个、4个以及更多的相连字符,你列举一下,很快就能发现规律,长度为n的一步字符串的子串个数为n*(n+1)/2。
来看个字符串 abchbcdaaacdbb
所有一步字符串就是这样分布的 abc h bcd a a a cd b b
发现没,这些一步字符串可以分开来求,你只要设一个sum表示总数,每求到一个一步字符串,就累加它的子串个数就行了。
至于题上说的,z的下一位是a,这个可以最后考虑,加上一个限制条件就行了。
注意,最后结果是是long long类型,因为有多个累加。
AC代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdio.h>
using namespace std;
typedef long long ll;
int main()
{
// freopen("input.txt","r",stdin);
std::ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
ll len;
cin>>len;
string str;
cin>>str;
ll length=1;
ll sum=0;
for(ll i=0;i<len;i++)
{
if(str[i]+1==str[i+1]||(str[i]=='z'&&str[i+1]=='a'))
{
length++;
}
else
{
sum+=length*(length+1)/2;
length=1;
}
}
cout<<sum<<endl;
}
return 0;
}
(--fxd)