整除子串
给定一个由数字组成的字符串 $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/
标签:子串,10,int,ret,str,整除 来源: https://www.cnblogs.com/onlyblues/p/16323287.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。