洛谷 B4185 [中山市赛 2024] 倍数子串 题解

B4185 [中山市赛 2024] 倍数子串 题解

完整题目

B4185 [中山市赛 2024/科大国创杯小学组 2023] 倍数子串/子串

题目背景

本题题面为 2024 年中山市赛版本,在题面主人公上与 2023 年安徽省科大国创杯小学组略有区别。

题目描述

Jimmy 对数字有着异于常人的热爱。有一天,他随便写出来一个数字——\(04320\),然后开始对着这个数字写写画画。他发现,从这个数字中随便选出连续的一段(Jimmy 把这个称为连续子串),有可能是 \(4\) 的倍数,例如 \(4\)\(04\)\(32\)\(432\) 等;也有可能是 \(5\) 的倍数,例如 \(20\)\(320\) 等。
Jimmy 的老师恰好路过此处,他向正沉迷于自己发现的 Jimmy 提了一个有趣的问题——给定一个指定的数字串,请问有多少连续子串是 \(4\) 或者 \(5\) 的倍数呢?
老师还特别提醒他:

  • 连续子串的开头可以是 \(0\)
  • 两个连续子串只要是从数字串中的不同位置选出来的,它们就>算是不同的;
  • 如果一个连续子串同时是 \(4\)\(5\) 的倍数,应当只被计算一次哦!

输入格式

一行一个数字串,长度为 \(n\)

输出格式

一行一个整数,表示所有的连续子串中,为 \(4\) 或者 \(5\) 的倍数的数量。

输入输出样例 #1

输入 #1

04320

输出 #1

11

输入输出样例 #2

输入 #2

2000

输出 #2

9

说明/提示

样例解释 1

所有满足题意的连续子串分别为:\(0\)\(04\)\(0432\)\(04320\)\(4\)\(432\)\(4320\)\(32\)\(320\)\(20\)\(0\)
其中有两个相同的 \(0\),这是因为它们是从数字串中的不同位置选出来的(一个在开头处,一个在结尾处)。

数据范围

  • 对于 \(10\%\) 的数据,保证 \(n = 1\)
  • 对于 \(60\%\) 的数据,保证 \(1 \leq n \leq 10^3\)
  • 对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 10^6\)

1. 读题

  • 其实关键句就一句:请问有多少连续子串是 4 或者 5 的倍数呢?
  • 0 也是 4 或者 5 的倍数。
  • 如果一个连续子串同时是 4 和 5 的倍数,应当只被计算一次

2. 解题思路

  • 逐一遍历字符串并进行判断,末尾是 0 或 5 的数为 5 的倍数,后两位能被 4 整除,为 4 的倍数。答案用变量 ans 记录。

3. 代码片段分析

  1. 遍历字符串:
for(int i=s.size()-1;i>=0;i--)
  1. 计算是否为 5 的倍数:
if(s[i]=='5'||s[i]=='0')//如果是 0 或 5,则为 5 的倍数。
  ans=ans+i+1;//累加。
  1. 计算是否为 4 的倍数:
		//减去字符 0 可以将字符转换为数字。 
	else if(((s[i]-'0')+(s[i-1]-'0')*10)%4==0){//判断末两位是 4 的倍数 
		ans=ans+i+1;
  1. 对于 4 的倍数需要特判

如果数字为 4 或 8 ,那么这个数也是 4 的倍数,但以其为末尾的数不一定是 4 的倍数,且以该数的这一位和上一位组成的十位数不一定为 4 的倍数,要特判。

1.if(s[i]=='2'||s[i]=='6')ans--;

2.if(s[i]=='4'||s[i]=='8')ans++;

4. AC 代码

代码片段中基本就是全部代码,如果你是这种情况,我只能引用一句 OI 界的名言:

十年 \(\operatorname{OI}\) 一场空,不开 \(\operatorname{long\hspace{1mm}long}\) 见祖宗

有任何问题请指出,如果对你有帮助,点个赞再走吧!谢谢!

posted @ 2025-07-15 07:52  sunhy2012  阅读(36)  评论(0)    收藏  举报