您的位置:首页 > 汽车 > 新车 > [蓝桥杯 2020 省 AB2] 子串分值

[蓝桥杯 2020 省 AB2] 子串分值

2024/7/8 1:48:54 来源:https://blog.csdn.net/m0_53295313/article/details/139074973  浏览:    关键词:[蓝桥杯 2020 省 AB2] 子串分值

一.题目

题目描述

对于一个字符串 S,我们定义 S 的分值 f(S)S 中恰好出现一次的字符个数。

例如 f(“aba”)=1,f(“abc”)=3, f(“aaa”) = 0

现在给定一个字符串 S[0…n−1](长度为 n),请你计算对于所有 S 的非空子串 S[i…j](0 ≤ i ≤ j < n), f(S[i…j]) 的和是多少。

输入格式

输入一行包含一个由小写字母组成的字符串 S

输出格式

输出一个整数表示答案。

数据范围

对于 20% 的评测用例,1 ≤ n ≤ 10
对于 40% 的评测用例,1 ≤ n ≤ 100
对于 50% 的评测用例,1 ≤ n ≤ 1000
对于 60% 的评测用例,1 ≤ n ≤ 10000
对于所有评测用例,1 ≤ n ≤ 100000

输入样例1

ababc

输出样例1

21

二.解释

看完题目,先交手暴力代码,暴力代码直接写就好,后面会给出来,只能过50%。

我们从单独一个字符入手,以 cababcab 为例,第四个字符为 a, 对于这个 a 来说,它对所有只包含这一个 a 的子串有贡献,即所有只包含这一个 a 的子串的 f() 值都有它。

省去其余字符只保留 a ,得 ·a·a··a,下标从 1 开始·。

设所有只包含中间 a 的子串数为 x,中间 a 下标为 K,左一个 a 下标位 L ,有一个 a 下标为 R;

a k a_k ak 左边取子串的首位有 (K - L) 种取法,右边取子串的末位有 (R - K) 种取法;

则:x = (K - L) * (R - K);

这一要注意一下边界情况:
a K a_K aK 为第一个 a 时,我们认为在下标 0 处有一个 a;
a K a_K aK 为最后一个 a 时,我们认为在下标 n + 1 处有一个 a;
这样按照上面的公式算出来的结果才是正确的。

三.代码

AC代码:
暴力代码:
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>using namespace std;typedef unsigned long long int64;
const int MaxN = 1e5 + 10;int InN, InK, Res;
string InS;
unordered_map<char, int> Hash[MaxN];
set<char> C[MaxN];int main()
{cin >> InS;for (int i = 0; i < InS.size(); i++){unordered_map<char, int> Map;	//从i开始每个字符的出现次数Map[InS[i]]++;int Count = 1;		//统计当前子串不重复字符的个数Res++;		//单独一个字符作为子串的情况for (int j = i + 1; j < InS.size(); j++){if (Map[InS[j]] == 1) { Res += --Count; }else if (Map[InS[j]] > 1) { Res += Count; }else { Res += ++Count; }Map[InS[j]]++;}}cout << Res;return 0;
}
AC代码:
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>using namespace std;typedef unsigned long long int64;
const int MaxN = 1e5 + 10;int64 InN, InK, Res;
string InS;
int L[MaxN], R[MaxN], Pre[30];	//对于下标为i的字符来说:L[i]左一个字串出现的下标,R[i]右一个字串出现的下标,Pre[i]临时存放上一个字符出现的位置int main()
{cin >> InS;//求L[i]for (int i = 1; i <= InS.size(); i++){//字符串下标默认从0开始,所以这里要减一int Tmp = InS[i - 1] - 'a';L[i] = Pre[Tmp];Pre[Tmp] = i;}//求R[i]for (int i = 0; i < 30; i++) { Pre[i] = InS.size() + 1; }for (int i = InS.size(); i > 0; i--){//字符串下标默认从0开始,所以这里要减一int Tmp = InS[i - 1] - 'a';R[i] = Pre[Tmp];Pre[Tmp] = i;}for (int i = 1; i <= InS.size(); i++){Res += (int64)(i - L[i]) * (R[i] - i);}cout << Res;return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com