作为一个合格的编程爱好者,刷题是必不可少的。那么,我们应该如何去完成每一道题呢?下面我就告诉你做一道题的基本步骤。
这里我们以去年小学组省赛第三题(Topscoding)为例。
第一步:读题
读题无疑是很重要的一步。认真、仔细的读题可以帮助我们更深刻的理解题意,使我们能更快、更高效的完成代码。
我们来看一下这题的题面(标题省略):
本题请以文件输入输出方式进行提交,输入输出文件名是
string.in
/string.out
题目背景
小可可和小多在研究数字串,他们在研究一个数字串的所有子串。
问题描述
给定一个长为 N 的数字串(即由若干 0 ∼ 9 的数字构成的字符串),请你回答有多少连续子串(即从该串中选出连续的若干个数字,可以包括前导 0 是 4 或 5 的倍数。如果同时是 4 和 5 的倍数,应当只被计算一次)。
输入格式
输入文件名为 string.in
。
第一行一个正整数 N,代表数字串的长度。
第二行一个长为 N 的数字串。
输出格式
输出文件名为 string.out
。
一行一个正整数,代表满足条件的子串数目。
样例
5
04321
6
解释#1
六个满足条件的串分别为 4, 432,32,0,04,0432。
样例#2
详见 选手文件夹 下的 string/string2.in/ans
文件。
数据范围
- 对于 10% 的数据:满足 N = 1。
- 对于 60% 的数据:满足 1 <= N <= 10^3。
- 对于 100% 的数据:满足 1 <= N <= 10^6。
第一眼我们就看到了文件提示,这意味着我们的代码前面需要加上
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
当然,递交的时候注释需要去掉。
接下来是题目背景,一般情况下对题目影响不大,所以可以简单扫一眼,直接过掉。
然后就是问题描述,在看这个地方的时候一定不要放过每一句话,因为有可能你忽略的那句话就是题目的关键。
我们再把题目-问题描述拿过来看:
给定一个长为 N 的数字串(即由若干 0 ∼ 9 的数字构成的字符串),请你回答有多少连续子串(即从该串中选出连续的若干个数字,可以包括前导 0 是 4 或 5 的倍数。如果同时是 4 和 5 的倍数,应当只被计算一次)。
从中我们可以得知,输入数据里包含一个由若干数字组成的数字串,做了那么多题目的你们一定也想到:这题和字符串
脱不了干系了。其次,我们要输出的是一个数(s),即为这个数字串里连续为4或5的倍数的可以有前导0的子串的个数。
是不是很绕?简单总结一下子串的条件:
1.首先你要知道那些子串需要是连续的
每个子串:
2. 为4或5的倍数,可有前导0。
第二项怎么判断呢?
由于数据范围过大,我们肯定不能把子串转为int
类型再做判断,这不仅麻烦还会超时。
你要知道,一个合格的编程者是需要掌握许多数学知识的。(如果一不小心刺痛了你向你道个歉~)
我们可以利用掌握的数学知识来解答:
4的倍数的数:后两位(/100)是4的倍数
5的倍数的数:最后一位是0或5
这不就有思路了!
5的倍数很好判断,直接找0或5,再动s就好了(具体待会说)
4的话可以单独弄一个函数来判断后两位:
bool df(char x, char y) {
if (int(x - '0') * 10 + int(y - '0') % 4 == 0) {
return 1;
}
return 0;
}
这不就OK了嘛。
至于如果同时是 4 和 5 的倍数,应当只被计算一次)。
就用if-else好了
看吧,仔细琢磨琢磨题目,一些基本的思路不就出来了吗。
至于输入输出格式和样例都有解释,自己看好了,这里不做详解。
数据范围一定要看!很多思路都是搭建在数据上面的。
第二步:写代码
最激动人心的写代码部分来了。
经过上面的基本思路,我们可以大致确定代码的框架:
#include <bits/stdc++.h>
using namespace std;
long long n, s;
string a;
bool df(char x, char y) {
if (((int(x - '0') * 10 + int(y - '0')) % 4) == 0) {
return 1;
}
return 0;
}
int main() {
//freopen("string.in", "r", stdin);
//freopen("string.out", "w", stdout);
cin >> n >> a;
for (int i = 0; i < a.size(); i++) {
//找子串
}
cout << s;
return 0;
}
其实我们发现,思路有后,代码很简单的!
现在只有找子串部分使我们需要考虑的了。至于其他的,都考虑过了啊!
我们可以怎样写呢?
首先是if-else语句(避免重复)判断4、5倍数,由于5更简单,先写他吧:
if (a[i] == '0' || a[i] == '5') {
s += (i + 1);
}
疑?为什么s是 += (i + 1)
呢?
因为,只要末尾是这两个数,子串就是5的倍数。,并且排除了前导0的情况,直接加上他的下标不就不用重复算了嘛!至于+1,那是因为i是从0开始的。
else语句呢?
else {
if (a[i] == '4' || a[i] == '8') {
s++;
}
if (i != 0 && df(a[i - 1], a[i])) {
s += i;
}
}
第一个很好理解,因为个位4、8那他就可以单独成为一个“合格”的子串了。
第二个,也很好理解,毕竟i>0
才能执行函数嘛!
那为什么第二个是s += i
而不是s += (i + 1)
呢?
那是因为你用的是两个if语句啊,+1在第一个已经过了
整体代码:
#include <bits/stdc++.h>
using namespace std;
long long n, s;
string a;
bool df(char x, char y) {
if (((int(x - '0') * 10 + int(y - '0')) % 4) == 0) {
return 1;
}
return 0;
}
int main() {
//freopen("string.in", "r", stdin);
//freopen("string.out", "w", stdout);
cin >> n >> a;
for (int i = 0; i < a.size(); i++) {
if (a[i] == '0' || a[i] == '5') {
s += (i + 1);
} else {
if (a[i] == '4' || a[i] == '8') {
s++;
}
if (i != 0 && df(a[i - 1], a[i])) {
s += i;
}
}
}
cout << s;
return 0;
}
第三步:自测
先编译给的样例,没过就逐行找错、自运行、加log……
过了,最好自己出几个极端样例(因为普通样例没有意义)
完,递交,过了(没过就继续按照评测提示找错)。
这就差不多了吧。
第四步:总结
相对来说这题还是比较简单的。总的来说做一道题,首先是读题,非常重要。思路基本是从这来的。后期编写和修正也很重要,不过这里需要自己去尝试、实践,这样你才能收获更多。
最后,也祝大家能在编程之路上越走越稳,越走越远,越来越强大!
标签:基本,子串,数字串,string,int,步骤,一道,倍数,return From: https://www.cnblogs.com/Yzc-wm/p/18082577