蓝桥杯 子串分值(算贡献)

本文介绍了一种高效算法,通过一次遍历解决长度为1e5的字符串中每个字母的累计贡献问题,关键在于利用最近两次出现位置记录来计算贡献。作者提供了C++代码示例,展示了如何用b数组存储字母及其最近出现位置,最终求和得到总贡献。
摘要由CSDN通过智能技术生成

在这里插入图片描述在这里插入图片描述

思路

一开始看到数据范围,n=1e5,那么只可以遍历一次,那么如何在一次之内算出全部贡献?细心一些可以发现对于字母来说只有26个,这便是本题的突破口,我们只需在这一次遍历内算出每个字母的贡献即可。
首先将子串分为n类—以第i号元素为结尾的子串(1<=i<=n)
a对于以第i号元素为结尾类子串的贡献
=0(第i号元素之前没出现过a)
=a出现时的位置(在第i号元素之前a只出现过一次)
=最近两次a出现过的位置之差(在第i号元素出现之前a出现两次以上)
由上知道我们所需记录的信息就是在当前第i号元素之前最近两次各元素出现的位置。
最后全部的贡献就是所有26个子母贡献相加即可。

Code

#include<iostream>
using namespace std;
const int Max = 1e6 + 5;

int b[30][2];//b[30]是26个字母,b[x][1]是x字母最近出现的位置,b[i][0]是x字母第二个最近出现的位置

int value()
{
	int sum = 0;
	for (int i = 1;i <= 26;i++)
	{
		if (b[i][0] != 0 && b[i][1] == 0)sum += b[i][0];
		else if (b[i][0] != 0 && b[i][1] != 0)sum += b[i][1] - b[i][0];
	}
	return sum;
}

int main()
{
	string str;cin >> str;
	str.insert(str.begin(), '#');//只是为了凑个位置令个元素位置+1
	long long ans = 0;
	for (int i = 1;i < str.size();i++)
	{
		int t = str[i] - 'a' + 1;
		if (b[t][0] == 0)b[t][0] = i;
		else if (b[t][0] != 0 && b[t][1] == 0)b[t][1] = i;
		else b[t][0] = b[t][1], b[t][1] = i;
		ans += value();
	}
	cout << ans;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Rikka_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值