蓝桥杯真题:字串分值

文章描述了一种计算给定字符串中所有非空子串的独特字符分值之和的方法,使用贡献法进行优化,通过记录每个字符的左右边界来快速确定独特字符的数量。
摘要由CSDN通过智能技术生成

题目:

对于一个字符串 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%20% 的评测用例,1≤n≤10;
对于 40%40% 的评测用例,1≤n≤100;
对于 50%50% 的评测用例,1≤n≤1000;
对于 60%60% 的评测用例,1≤n≤10000;
对于所有评测用例,1≤n≤100000。

输入样例:
ababc
输出样例:
21
样例说明

所有子串 f值如下:

a     1
ab    2
aba   1
abab  0
ababc 1
 b    1
 ba   2
 bab  1
 babc 2
  a   1
  ab  2
  abc 3
   b  1
   bc 2
    c 1

题目分析:

这个题目可以采用暴力法和贡献法,这里我们采用贡献法来写代码;

        我们从后面往前面分析,首先是例如有一个a(位置为i),它左边的第一个a(假设位置为l),它右边的第一个a(假设位置为r),所以有sum=(i-l)*(r-l)种可能,所以它在总的个数里面的个数为sum,同理我们只需要求每一个字符左右两端的第一个相同字符的位置,左边没有则为0,右边没有相同的则为n+1,再把所有字符的这个sum相加就是总的个数。

代码如下:(代码里面带有注释,看不懂可以发评论或者私聊我给你讲解)

#include<stdio.h>
#include<string.h>
char arr[100005];
typedef long long LL;//因为个数可能超过int的存储范围所以采用LL存储数据
int l[100005],r[100005],p[26]={0};//l数组用于保存它左边第一个相同的元素,r数组用于保存右边第一个相同元素的位置(以这个字符为起点)
//p数组初始为0,因为这个时候其左边是没有相同的元素的
int main()
{
    LL sum=0;
   scanf("%s",arr+1);//将数据保存在arr数组里面
   int n=strlen(arr+1);//记录字符的总的个数
   for(int i=1;i<=n;i++)
   {
       int t=arr[i]-'a';//找到这个字符对应的p数组的位置
       l[i]=p[t];//将这个元素左边第一个相同元素的位置保存在l数组里面
       p[t]=i;//修改p[t],因为对于下一个相同的元素,它左边第一个相同元素为这个元素的位置
   }
   for(int i=0;i<26;i++)p[i]=n+1;//修改p[t],用于保存其右边相同元素的位置
   for(int i=n;i>=1;i--)
   {
       int t=arr[i]-'a';//找到这个字符对应的p数组的位置
       r[i]=p[t];//将这个元素右边第一个相同元素的位置保存在r数组里面
       p[t]=i;//修改p[t],因为对于下一个相同的元素,它右边第一个相同元素为这个元素的位置
   }
   for(int i=1;i<=n;i++)
   sum+=(LL)(i-l[i])*(r[i]-i);//计算总和
   printf("%lld",sum);//输出个数
   return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值