1. OJ(online judge)题⽬输⼊情况汇总
在竞赛的 OJ 题⽬中,⼀般关于输⼊场景总结为下⾯四类:
接下来,我们就结合题⽬,给⼤家分别介绍。
1.1 单组测试⽤例
练习1 B2009 计算 (a+b)/c 的值 - 洛谷 | 计算机科学教育新生态 128
#include <iostream>
using namespace std;
int main()
{int a, b, c;//只处理一组数据cin >> a >> b >> c;cout << (a + b) / c << endl;return 0;
}
练习2:B2081 与 7 无关的数 - 洛谷 | 计算机科学教育新生态 128
#include <iostream>
using namespace std;
int main()
{int n = 0;cin >> n;int i = 1;int sum = 0;while (i <= n){if (i % 7 != 0 && i / 10 != 7 && i % 10 != 7)sum += i * i;i++;}cout << sum << endl;return 0;
}
1.2 多组测试⽤例
1.2.1 测试数据组数已知
练习1:多组输入a+b II 129
#include <iostream>
using namespace std;int main()
{int n = 0;int a = 0, b = 0;cin >> n;while (n--){cin >> a >> b;cout << a + b << endl;}return 0;
}
练习2:B2064 斐波那契数列 - 洛谷 | 计算机科学教育新生态 129
#include <iostream>
using namespace std;const int N = 40;
int arr[N] = {0,1,1};
int n,a;int main()
{cin >> n;for(int i = 3; i <= 30; ++i){arr[i] = arr[i-1] + arr[i-2]; } while(n--){cin >> a;cout << arr[a] << endl;}return 0;
}
练习3:B3769 [语言月赛202305] 制糊串 - 洛谷 | 计算机科学教育新生态 130
#include <iostream>
#include <string>
using namespace std;int main() {string s,t;int q;int l1,l2,r1,r2;cin >> s >> t >> q; while(q--){cin >> l1 >> r1 >> l2 >> r2;//输入的下标是从1开始的,string substr(size_t pos = 0, size_t len = npos) const string s1 = s.substr(l1-1,r1-l1+1);string t1 = t.substr(l2-1,r2-l2+1);if (s1 < t1) cout << "yifusuyi" << endl;else if (s1 > t1) cout << "erfusuer" << endl;else cout << "ovo" << endl;}return 0;
}
题⽬中说 "有 q 次询问",意思是程序要处理q组测试数据,(也就是对应 q 次循环),我们要针对每次询问,给出⼀个结果。 其实就是之前的单组测试变成了 q 组测试,在之前的代码上套⼀层 while 循环即可。当 有 q 次询问的时候, while(q--) 是⾮常⽅便的⽅式。然后就按照单组输⼊的⽅式处理每 组输⼊的数据就好了。
1.2.2 测试数据组数未知
练习1:多组输入a+b 131
#include <iostream>
using namespace std;
int a, b;
int main()
{while (cin >> a >> b){cout << a + b << endl;}return 0;
}
cin >> a; 会返回⼀个流对象的引⽤,即 cin 本⾝。在 C++ 中,流对象 cin 可以被⽤ 作布尔值来检查流的状态。如果流的状态良好(即没有发⽣错误),流对象的布尔值为 true 。如果发⽣错误(如遇到输⼊结束符或类型不匹配),布尔值为 false 。 在 while (cin >> a >> b) 语句中,循环的条件部分检查 cin 流的状态。如果流成 功读取到2个值, cin >> a >> b 返回的流对象 cin 将被转换为 true ,循环将继 续。如果读取失败(例如遇到输⼊结束符或⽆法读取到2个值), cin >> a >> b 返回的 流对象 cin 将被转换为 false ,循环将停⽌
练习2:数字三角形 131
#include <iostream>
using namespace std;int main()
{int n;while(cin >> n){//打印行for(int i = 1; i <=n; ++i){//打印每一行的元素for(int j = 1; j <= i; ++j){cout << j << " ";}cout << endl;}}return 0;
}
练习3:定位查找 132
#include <iostream>
using namespace std;const int N = 25;
int arr[N];
int n,m;int main()
{while(cin >> n){for(int i = 0; i < n; ++i){cin >> arr[i];}cin >> m;int i = 0;for(i; i < n; ++i){if (m == arr[i]) {cout << i << endl;break;}}//最好在题目中复制if (i == n) cout << "No" << endl;}return 0;
}
1.2.3 特殊值结束测试数据
练习1:字符统计 133
#include <iostream>
using namespace std;int l,d,o; int main()
{int ch = 0;while((ch = getchar()) != '?') {if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' ) l++;else if (ch >= '0' && ch <= '9') d++;else o++;}cout << "Letters=" << l << endl;cout << "Digits=" << d << endl;cout << "Others=" << o << endl;return 0;
}//islower isupper isdigit
#include <iostream>
#include <string>
#include <cctype>
using namespace std;int l,d,o;int main()
{int ch = 0;while((ch = getchar()) != '?') {if (islower(ch) || isupper(ch)) l++;else if (isdigit(ch)) d++;else o++;}cout << "Letters=" << l << endl;cout << "Digits=" << d << endl;cout << "Others=" << o << endl;return 0;
}//isalpha
#include <iostream>
#include <string>
#include <cctype>
using namespace std;int l,d,o;int main()
{int ch = 0;while((ch = getchar()) != '?') {if (isalpha(ch)) l++;else if (isdigit(ch)) d++;else o++;}cout << "Letters=" << l << endl;cout << "Digits=" << d << endl;cout << "Others=" << o << endl;return 0;
}//getline
#include <iostream>
#include <string>
#include <cctype>
using namespace std;int l,d,o;int main()
{string s;getline(cin, s);s.pop_back();//删掉?最后一个字符 for(auto ch : s){if (isalpha(ch)) l++;else if (isdigit(ch)) d++;else o++;}cout << "Letters=" << l << endl;cout << "Digits=" << d << endl;cout << "Others=" << o << endl;return 0;
}
练习2:多组数据a+b III 134
#include <iostream>
using namespace std;
int main()
{int a = 0, b = 0;//逗号表达式特点//1.从左向右依次计算//2.整个表达式结果是最后一个表达式的结果 while (cin >> a >> b, a || b){cout << a + b << endl;}return 0;
}
2. 输⼊时特殊技巧
2.1 技巧1:含空格字符串的特殊处理⽅式
根据我们现在掌握的知识,含空格的字符串,如要读取有 fgets 、 scanf 、 getchar 、 getline 四种⽅式解决,但是有时候,根据题⽬的情况,不⼀定⾮要完整的 读取这个带空格的字符串, ⽽是将字符串中空格隔开的每⼀个字符串,当做⼀个单词处理更⽅便,也避免了读取带空格字符串的各种问题。
练习:B2109 统计数字字符个数 - 洛谷 | 计算机科学教育新生态 135
解法1:读取整个带空格的字符串分析
//getline
#include <iostream>
#include <string>
#include <cctype>
using namespace std;int main() {string s;getline(cin, s);int c = 0;for(auto ch : s){if (isdigit(ch)) c++;}cout << c << endl;return 0;
}
解法2:按照多个单词分析
//cin
#include <iostream>
#include <string>
#include <cctype>
using namespace std;int main() {string s;int c = 0;while(cin >> s){for(auto ch : s){if (isdigit(ch)) c++;}}cout << c << endl;return 0;
}
2.2 技巧2:数字的特殊处理⽅式
当我们程序运⾏的时候,在控制台输⼊ 123 的时候,这时的 123 是三个字符, 123 是⼀个字符序列,程序会根据代码中的数据类型,可能将 123 解析成整型,也可能将 123 解析成字符串。 ⽐如:
int num = 0;
cin >> num;//输⼊123, 就被解析成整数
string s;
cin >> s; //输⼊123, 就被解析成字符串
这⾥的解析的⽅式,主要是依赖编译器对变量类型的识别,根据类型再将读取字符串数据转化成对应类型的数据。 我们在写代码的时候,应该根据实际的情况,来决定如何处理输⼊的内容。
练习:小乐乐改数字_牛客题霸_牛客网 136
解法1:当做整数读取
//double pow (double base, double exponent);#include <iostream>
#include <cmath>
using namespace std;int main() {int n;cin >> n;int ret = 0;int i = 0;while(n){if (n % 10 % 2)ret += pow(10,i);n /= 10;++i;}cout << ret << endl;return 0;
}
解法2:当做字符串处理
#include <iostream>
#include <string>
#include <cmath>
using namespace std;int main() {string s;cin >> s;for(int i = 0; i < s.size(); ++i){//'0' = 48//'1' = 49if (s[i] % 2)s[i] = '1';else s[i] = '0';}cout << stoi(s) << endl;return 0;
}
3. scanf/printf 和 cin/cout的对⽐
scanf 和 printf 是 C 语⾔中的标准输⼊输出函数,⽽ cin 和 cout 是 C++ 语⾔中的标准输⼊输出流对象。它们各⾃有优缺点,整体上来说 cin 和 cout 会更加⽅便,但有时候我们也不得不 使⽤ scanf 和 printf 。
3.1 格式控制差异
·scanf 和 printf 不能⾃动识别输⼊数据的类型,需要⼿动指定格式字符串,容易出现格式错误。开发者需要确保格式字符串与变量类型匹配,否则会导致未定义⾏为。·cin 和 cout 会根据变量类型⾃动处理输⼊输出,避免格式化错误。相对 scanf 和 printf⽽且,C++的 cin 和 cout 更加易⽤。·scanf 和 printf :格式化输出更精确直观,特别适合复杂格式的输⼊输出,⽐如:在要求指定格式输出的时候, printf 函数就⽐ cout 更加⽅便和灵活。
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{float a = 3.50;double d = 16.50;cout << "cout: " <<a << " "<< d <<endl;printf("printf: %f %lf\n", a, d);return 0;
}
//cout: 3.5 16.5
//printf: 3.500000 16.500000
1. cout 默认不会输出六位⼩数,⾃动忽略⼩数点后多余的 0 , printf 函数打印浮点数的时候,⼩数点默认打印6位。2. cout 在输出的时候不需要指定格式, printf 则需要明确的格式。
3.2 性能差异
3.2.1 案例演⽰
结论: scanf 和 printf 通常⽐ cin 和 cout 快。原因: cin 和 cout 由于要考虑兼容C语⾔的输⼊和输出,封装实现的更加复杂,通常⽐ scanf 和 printf 稍慢,但这种差异在⼤多数应⽤场景中可以忽略不计。 但是在竞赛的题⽬中,尤其是当输⼊、输出数据量较⼤时,使⽤ cin 和 cout 完成输⼊输出,经常 会出现 Time Limit Exceeded 的情况。⽽ scanf 和 printf 就不存在类似的问题。下⾯给⼤ 家准备了两个案例。