整除子串

整除子串

给定一个由数字组成的字符串 $s$,请你计算能够被 $4$ 整除的 $s$ 的子串数量。

子串可以包含前导 $0$。

例如,如果 $s$ 为 124 ,则满足条件的子串有 $4$ 个: 12 , 4 , 24 , 124 ;如果 $s$ 为 04 ,则满足条件的子串有 $3$ 个: 0 , 4 , 04 。

输入格式

一个由数字组成的字符串 $s$。

输出格式

一个整数,表示满足条件的子串数量。

数据范围

前 4 个测试点满足 $1 \leq \left| s \right| \leq 10$。
所有测试点满足 $1 \leq \left| s \right| \leq 3 \times {10}^{5}$。

输入样例1:

124

输出样例1:

4

输入样例2:

04

输出样例2:

3

输入样例3:

5810438174

输出样例3:

9

 

解题思路

  $4 \mid n$的充分必要条件是$4$能整除$n$的末两位。把$n$拆成两部分,末两位为$ab$,前面剩余的位为$m$,即有$n = mab$,那么有$n = m \times 100 + ab$,其中不管$m$是什么,$4$都能整除$m \times 100$,因此$4 \mid n$等价于$4 \mid ab$。

  因此我们可以枚举区间的右端点,看前面有多少个左端点使得这个区间组成的数能够被$4$整除,只需要看最后两位数$i-1$和$i$组成的数能否被$4$整除,如果可以被$4$整除,那么左端点可以取前面任何一个值(从$0 \sim i - 1$,共$i$个)。如果两位数不能被$4$整除,那么无论前面取什么都不能被$4$整除,即能够被$4$整除的子串数为$0$。还需要特判一下字串长度为$1$的情况,只需要看这一位能否被$4$整除。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 3e5 + 10;
 5 
 6 char str[N];
 7 
 8 int main() {
 9     scanf("%s", str);
10     
11     long long ret = 0;
12     for (int i = 0; str[i]; i++) {
13         if ((str[i] - '0') % 4 == 0) ret++; // 特判长度为1的子串
14         // 子串长度大于1的情况,看末两位能否被4整除
15         if (i && ((str[i - 1] - '0') * 10 + (str[i] - '0')) % 4 == 0) ret += i;
16     }
17     
18     printf("%lld", ret);
19     
20     return 0;
21 }

  这题还可以用dp来做。一开始太死板了,没想到当前状态是可以从上一次的哪个状态转移过来,其实可以反过来思考,可以通过当前状态可以转移到下一个的哪个状态来进行状态的计算。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 3e5 + 10;
 7 
 8 char str[N];
 9 int f[N][4];
10 
11 int main() {
12     scanf("%s", str + 1);
13     
14     for (int i = 0; str[i + 1]; i++) {
15         f[i + 1][(str[i + 1] - '0') % 4]++; // 长度为1的子串
16         for (int j = 0; j < 4; j++) {
17             f[i + 1][(j * 10 + str[i + 1] - '0') % 4] += f[i][j];   // 从当前状态转移到下一个状态
18         }
19     }
20     
21     LL ret = 0;
22     for (int i = 1; str[i]; i++) {
23         ret += f[i][0]; // 结果是枚举所有以右端点结尾,构成的数模4为0的字串数量
24     }
25     printf("%lld", ret);
26     
27     return 0;
28 }

 

参考资料

  AcWing 4426. 整除子串(AcWing杯 - 周赛):https://www.acwing.com/video/3897/

posted @ 2022-05-29 13:39  onlyblues  阅读(102)  评论(0编辑  收藏  举报
Web Analytics