子串分值和满分解法
一、完整题目
二、具体思路
1.暴力递归
利用递归的思想,求出每一个字串,并统计每一个字串的分值,最后进行统计累加,求得结果,求字串的顺序为:
- 首先,一个完整的串,将一个完整的串每次去点最后一个字符
- 再次,去掉串的首个字符,重复1的操作
- 重复2的操作直至串为空
在求出每个子串,统计字符数量即可
2.统计贡献值
正常求字串要横向一行一行看,我们把思路打开,竖着看,看每一列的字符出现了几次,将次数统计起来即可,在网上找到了一个示意图:
来源:https://img-blog.csdnimg.cn/20210413181240678.png
可以总结出公式:
- 该字符第一次出现时:出现次数=(下标+1)x(字符串长度-下标)
- 该字符之前出现过时:出现次数=(字符串长度-下标)x(当前位置-之前出现的位置)
三、编写代码
1.暴力递归
#include <stdio.h>
#include <string.h>
#define MAX 100000//最大长度
int difStr(char s[],int len)//求字串的分值
{
if(len==0) return 0;//结束条件
int i,cnt=0;
int a[26]={0};//统计是否存在
for(i=0;i<len;i++) a[s[i]-'a']++;//计数
for(i=0;i<25;i++) if(a[i]!=0) cnt++;//统计出现不同字母的个数
cnt+=difStr(s,len-1);//递归实现
return cnt;//返回此字串的分值
}
int f(char s[],int len)//统计所有字串的分值和
{
if(len==0) return 0;//结束条件
int sum=0;//分值和
sum+=difStr(s,len);//求出此轮递归的字串分值和
sum+=f(s+1,len-1);//递归求出其他字串的和
return sum;//返回所有字串的分值和
}
int main()
{
char s[MAX];//开数组
int sum,len;
scanf("%s",&s);//输入字符串
len=strlen(s);//求输入的字符串长度
printf("%d",f(s,len));//打印结果
return 0;
}
2.统计贡献值
#include<stdio.h>
#include<string.h>
#define MAX 100000//最大长度
typedef long long int LLint;
int main()
{
LLint i,len,sum=0;
int a[26]={0}; //用于统计出现的字符数
char s[MAX];
scanf("%s",s);//输入字符串
len=strlen(s);//求输入字符串长度
//求字串分值和
for(i=0;i<len;i++)
{
if(a[s[i]-'a']==0)//判断该字符是否出现过
{
sum=sum+(i+1)*(len-i);//把单个字符的值加起来
a[s[i]-'a']=i+1;//保存字符的位置
}
else
{
sum=sum+(i+1-a[s[i]-'a'])*(len-i);//之前出现过的字符,现在再次出现的值
a[s[i]-'a']=i+1;//更新位置
}
}
printf("%lld",sum);//打印输出
return 0;
}
四、测评结果
1.暴力递归
只过了50%的测试点,之后的测试点会超时
2.统计贡献值
五、总结评价
综上可以看出,递归的方法虽然思路清晰,编写简单,但是比较暴力时间复杂度较高;而统计贡献值的方法,不容易想到,但是十分简单。
所以,假如我们是生活在一幅画中,要时常跳出来,看一看画的全貌,在跳回去,而不是埋头苦干,有时候选择比努力更重要。
有问题欢迎各位大佬指出
蓝桥杯系列将持续更新,欢迎关注,一起学习