牛客赛练习赛-A嘤嘤的签到,详细题解

题目描述 :
本来这一场比赛是小白月赛,但是因为嘤嘤的题目越出越难,就只能变成练习赛了呢!但大部分的题目还是小白难度,相信大家都能AK,但是为了以防万一,嘤嘤还是放一题血签吧!
嘤嘤突然发现,今天好像是一个攻击性很强的日子,除此之外,下个月的今天和上上上个月的今天都是很臭的日子,上上个月的今天又是小木曾雪菜的生日,上个月的今天还是 π 节。
世界名画——《你为什么这么熟练啊!》(妮露(左),神里绫华(中),荧(右))
在op414、哼哼啊啊啊、届不到、高等(su)数(tui)学的轮番刺激下,嘤嘤已经对同时出现1、4这两个数字的数字串PTSD了,嘤嘤嘤!

 题目太抽象,我们分析后得到以下结论:

 给你一个字符串,问你这个字符串中没有同时出现‘1’和‘4’的字串个数。

 是不是很简单呀???NONONO。

 问题在于,这个题目的时间要求

不然还真挺简单的(笑)

所以!我们必须用O(n^2)复杂度以下的方法来实现!

那么,再仔细分析一下我们可以得知~

只要能想到我们要判断数组中,‘1’和‘4’出现的位置,来进一步优化算法。

你就成功一大半了!  讲一种解法。

我们先记录数组中‘1’和‘4’出现的位置,实现如下

for(int i=1;i<=n;i++){//n是字符串长度
		a[s[i]] = i;//记录数字出现的位置
		//等会再告诉你
	}

现在,我们可以很容易得知,

最后一个1和4的位置中靠左的那一个往右都是合法的。

​ 例如,041004080,枚举第8个位置时,最后一个1在第3个位置,最后一个4在第6个位置,最左边的位置是3,因此,00408,0408,408,08,8都是合法子串。

所以,我们可以得出 只要用当前位置(即 i )减去 最后一个‘1’或‘4’中位置靠前的位置 即储存过的a['1']或a['4']中较小的那个。就可以得出所有合法的字串。(因为这个字串里必然不会同时存在1或者4。)(顺便一提,n个字符组成的字符串,必然可以分为n-1个字串,加上自己就是n个)

得出以下式子:ans+=i-min(a['1'],a['4'])

补全循环

for(int i=1;i<=n;i++){
		a[s[i]] = i;
		ans += i - min(a['1'] , a['4']);
	}

看不懂?再举一个例子

比如字符串 023114514

遍历第六个位置时,i=5,a['4']=5,a['1']=4。那么min(a['1'],a['4'])=4,符合条件的子串为‘4’,‘023114’‘23114’‘3114’‘114’‘14’均不符合。仅有一个字串符合条件,i-min(a['1'],a['4'])得出的答案也是1。

遍历第七个位置时,i=6,a['4']=5,a['1']=4。那么min(a['1'],a['4'])=4,符合条件的字串为‘45’‘5’,因为‘0231145’‘231145’‘31145’‘1145’‘145’均不符合。仅有两个字串符合条件,i-min(a['1'],a['4'])得出的答案也是2。

之后我们补全剩余代码即可

#include<bits/stdc++.h>

using namespace std;

using LL = long long;

int main(){
	int n;
	cin>>n;
	string s;
	cin>>s;
	s = " " + s;
	vector<int> a(200);
	LL ans = 0;
	for(int i=1;i<=n;i++){
		a[s[i]] = i;
		ans += i - min(a['1'] , a['4']);
	}
	cout<<ans<<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值