乒乓球
作者: ZhouMingLiang
时间限制: 10s
章节: 字符串
问题描述
国际乒联主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。明明就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。在开展他的研究之前,明明首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。 (注:11(21)分制,在一局比赛中,选手A先得到11(21)分且此时领先选手B 2分或2分以上时,则选手A赢得此局;若当双方打成10(20)平后,则先多得2分的一方为胜方,赢得此局。)
明明通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。一局比赛的开始比分为0比0。 比如现在有这么一份记录,(其中W表示明明获得一分,L表示明明的对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW
在11分制下,此时比赛的结果是明明第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。
在21分制下,此时比赛结果是明明第一局21比0获胜,正在进行第二局,当前比分2比1。
再如有这么一份记录,(其中W表示明明获得一分,L表示明明的对手获得一分):
WLWLWLWLWLWLWLWLWLWLWLWLWL
在11分制下,此时比赛的结果是明明和对手打成13比13,这局比赛仍没有分出胜负,因为任何一方都没有领先其对手2分。
在21分制下,此时比赛的结果是明明和对手打成13比13,这局比赛仍在进行中。
由于明明参加过多年的比赛,比赛的数据量相当庞大,如果仅仅使用手工统计,在短时间内统计出结果对于明明来说是相当困难的。因此明明求助于你,希望你能写一个程序,帮助他快速地统计出结果来。
明明的问题可以归结为:给你一系列的比赛数据(WL形式),分别按照11分制和21分制的比赛规则进行统计,然后输出统计结果。
输入说明
你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每行包括一串有W、L和E组成比赛结果,其中W表示明明得一分,L表示明明的对手得一分,E表示该组测试数据的结束,也就是说E后面的W、L应该忽略,无需处理。每行的长度不会超过30个字符。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明
对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将每组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。
每组运算结果由两部分组成,其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。
每部分由若干行组成,每一行对应一局比赛的比分(按比赛信息输入顺序),每局的比分按如下形式表示:m:n,其中m表示明明的得分,n表示明明的对手的得分,m、n之间用一个冒号隔开。
输出时,每组运算结果与其后一组运算结果之间有一个空行,第一组运算结果前面以及最后一组运算结果后面没有任何空行或其他任何字符。 注:通常,显示屏为标准输出设备。
输入范例
WWWWWWWWWWLLLLLLLLLLL
WWWWWWWWWLLLLLLLLLE
LLLLLLLLLLLLLLLLLE
输出范例
13:11
6:9
19:20
0:11
0:6
0:17
个人总结
- 终止符处理核心 :找到 'E' 后,通过
substr(0, e_pos)截取有效字符,避免无效字符干扰统计; - 比分结算规则 :
- 11 分制:
(w≥11 || l≥11) && |w-l|≥2; - 21 分制:
(w≥21 || l≥21) && |w-l|≥2;
- 11 分制:
- 代码复用:将重复的统计逻辑封装为函数,通过参数区分规则,提升可维护性;
代码
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
string str,str_temp;
while(getline(cin,str_temp)) {
str+=str_temp;
auto it = str.find('E');
if(it!=string::npos) { //找到了E
str.erase(it);//把E和后面的字符都删掉
int cnt_w_11 = 0,cnt_l_11 = 0;
for(int i = 0; i<str.size(); ++i) {
if(str[i] == 'W')
++cnt_w_11;
if(str[i] == 'L')
++cnt_l_11;
if((cnt_l_11>=11 || cnt_w_11 >=11) && abs(cnt_l_11-cnt_w_11)>=2) {
cout<<cnt_w_11<<":"<<cnt_l_11<<endl;
cnt_w_11 = cnt_l_11 = 0;
}
}
if(!(cnt_w_11 == 0 && cnt_l_11 == 0))
cout<<cnt_w_11<<":"<<cnt_l_11<<endl;
cout<<endl;//第一部分与第二部分之间的空行
int cnt_w_21 = 0,cnt_l_21 = 0;
for(int i = 0; i<str.size(); ++i) {
if(str[i] == 'W')
++cnt_w_21;
if(str[i] == 'L')
++cnt_l_21;
if((cnt_l_21>=21 || cnt_w_21 >=21) && abs(cnt_l_21-cnt_w_21)>=2) {
cout<<cnt_w_21<<":"<<cnt_l_21<<endl;
cnt_w_21 = cnt_l_21 = 0;
}
}
if(!(cnt_w_21 == 0 && cnt_l_21 == 0))
cout<<cnt_w_21<<":"<<cnt_l_21<<endl;
str.clear();//str字符串清空,准备拼接下一个字符串
cout<<endl;
}
}
return 0;
}
字符串统计
作者: SunCiHai
时间限制: 10s
章节: 字符串
问题描述
明明最近在做一个有关字符串的统计工作。两个由小写字母组成的字符串s1和s2,明明需要统计出以下四种关系:
(1)在s1或s2中存在的字母(包括在s1和s2中都存在的字母);
(2)在s1中且在s2中的字母;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母;
(4)不在s1中且也不在s2中的字母;
例如两个字符串s1为"lkjsvoahs",s2为"qglhskjdfg":
(1)在s1或者在s2或者s1、s2中都存在的字母:adfghjkloqsv;
(2)在s1中且在s2中的字母:hjkls;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母:adfgoqv;
(4)不在s1中且也不在s2中的字母:bceimnprtuwxyz;
明明统计了很久,但是由于统计过程十分繁琐,且很容易出错,导致明明的进度非常慢,很有可能因为统计不完而错过了晚上的约会。因此明明想请你帮个忙,帮他写一个程序,用程序来统计出以上几项内容。
明明的问题可以归结为:
输入两串由小写字母组成的字符串s1和s2,比较其中的字母,输出以下四项,输出的字母以字典顺序排列:
(1)在s1或s2中存在的字母(包括在s1和s2中都存在的字母);
(2)在s1中且在s2中的字母;
(3)在s1中但不在s2中的字母,在s2中但不在s1中的字母;
(4)不在s1中且也不在s2中的字母;
例如字符串s1为sadf,s2为asdf,则需输出以下四行(注意输出的格式):
in s1 or s2:adfs
in s1 and s2:adfs
in s1 but not in s2 ,or in s2 but not in s1:
not in s1 and s2:bceghijklmnopqrtuvwxyz
输入说明
你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每组测试数据两行,每组测试数据的第一行为字符串s1,每组测试数据的第二行为字符串s2;s1和s2都由小写英文字母组成,且长度不超过26个字符。测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明
对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将这一组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。
每组运算结果由四行组成:
第一行为在s1或者在s2或者s1、s2中都存在的字母;
第二行为在s1中且在s2中的字母;
第三行为在s1中但不在s2中的字母,在s2中但不在s1中的字母;
第四行为不在s1中且也不在s2中的字母;
具体格式请参考样例输出。
每组运算结果其行首和行尾都没有任何空格,每组运算结果与其后一组运算结果之间有一个空行,最后一组运算结果后面没有空行。
注:通常,显示屏为标准输出设备。
输入范例
sadf
asdf
lkjsvoahs
qglhskjdfg
输出范例
in s1 or s2:adfs
in s1 and s2:adfs
in s1 but not in s2 ,or in s2 but not in s1:
not in s1 and s2:bceghijklmnopqrtuvwxyz
in s1 or s2:adfghjkloqsv
in s1 and s2:hjkls
in s1 but not in s2 ,or in s2 but not in s1:adfgoqv
not in s1 and s2:bceimnprtuwxyz
个人总结
- 集合运算核心:用长度为 26 的布尔数组标记字符存在性,是小写字母集合运算的最优方式(时间 / 空间复杂度均为 O (1));
- 集合判断规则 :
- 并集:
in_s1 || in_s2 - 交集:
in_s1 && in_s2 - 对称差集:
in_s1 ^ in_s2(异或,等价于 "仅一个存在") - 补集:
!in_s1 && !in_s2
- 并集:
- 格式控制 :通过计数器
case_count控制组间空行,避免开头 / 结尾多余空行;
代码
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1, s2;
int case_count = 0; // 记录测试用例数,控制组间空行
while (cin >> s1 >> s2) {
// 组间空行:非第一个用例前输出空行
if (case_count > 0) {
cout << endl;
}
case_count++;
// 初始化标记数组:s1_flag[i] = true 表示字符'a'+i在s1中出现
bool s1_flag[26] = {false};
bool s2_flag[26] = {false};
// 标记s1中出现的字符
for (char c : s1) {
s1_flag[c - 'a'] = true;
}
// 标记s2中出现的字符
for (char c : s2) {
s2_flag[c - 'a'] = true;
}
// 1. 并集:s1或s2中存在的字符
string union_str;
for (int i = 0; i < 26; i++) {
if (s1_flag[i] || s2_flag[i]) {
union_str += (char)('a' + i);
}
}
cout << "in s1 or s2:" << union_str << endl;
// 2. 交集:s1且s2中存在的字符
string intersect_str;
for (int i = 0; i < 26; i++) {
if (s1_flag[i] && s2_flag[i]) {
intersect_str += (char)('a' + i);
}
}
cout << "in s1 and s2:" << intersect_str << endl;
// 3. 差集:仅s1 或 仅s2中存在的字符
string diff_str;
for (int i = 0; i < 26; i++) {
if ((s1_flag[i] && !s2_flag[i]) || (!s1_flag[i] && s2_flag[i])) {
diff_str += (char)('a' + i);
}
}
cout << "in s1 but not in s2 ,or in s2 but not in s1:" << diff_str << endl;
// 4. 补集:都不存在的字符
string complement_str;
for (int i = 0; i < 26; i++) {
if (!s1_flag[i] && !s2_flag[i]) {
complement_str += (char)('a' + i);
}
}
cout << "not in s1 and s2:" << complement_str << endl;
}
return 0;
}
隐藏口令
作者: 5.5.2
时间限制: 1s
章节: 字符串
问题描述
有时候程序员有很奇怪的方法来隐藏他们的口令。
Billy"Hacker"Geits会选择一个字符串S(由L个小写字母组成,5<=L<=100,000),然后他把S顺时针绕成一个圈。
如字符串cbadfa,绕成一个圈后,我们认为字符串首尾相连。
每次取其中一个字母作为起始字母,并顺时针依次取字母而组成一个字符串。这样将得到一些字符串。
比如字符串cbadfa,按照以上规则取出的字符串有:
cbadfa badfac adfacb dfacba facbad acbadf
我们找到最小的那个字符串,可知为acbadf,也可知道它的第一个字符'a'在原字符串cbadfa中为第6个字符(位置从1开始),
将得到的结果6减1得到5,这就是我们需要的口令。
再比如字符串alabala,绕成一个圈后,每次取其中一个字母作为起始字母,并顺时针依次取字母而组成一个字符串。这样将得到一些字符串:
alabala labalaa abalaal balaala alaalab laalaba aalabal
我们找到最小的那个字符串,可知为aalabal,它的第一个字母'a'在原字符串中位置为7,7-1=6,则6为口令。
注:如果按照规则有两个字符串都是最小的,则取前面那一个。
输入说明
第一行:一个数L
第二行及之后:字符串S。
注意:字符串S可跨多行,但其中的'\n'不算成S中的字符
输出说明
一行,为得到的口令。
无多余空格或空行。
输入范例
6
cbadfa
输出范例
5
个人总结
最小表示法核心逻辑(算法本质)
- 双指针
i=0、j=1分别代表两个候选起始位置,k是当前比较的字符偏移量; - 比较
s[(i+k)%L]和s[(j+k)%L]:- 字符相等 →
k++继续比较下一个; - 字符不等 → 淘汰较大的指针(
i += k+1或j += k+1),重置k=0;
- 字符相等 →
- 最终返回
min(i,j)作为最小起始下标,时间复杂度为 O(n),是该问题的最优解。
代码
cpp
#include <iostream>
#include <string>
#include <algorithm> // 用于min函数
using namespace std;
// 最小表示法:返回环形字符串的最小起始下标(从0开始)
int minimalRepresentation(const string& s) {
int L = s.size();
int i = 0, j = 1, k = 0;
while (i < L && j < L && k < L) {
// 计算当前比较的字符(环形取模)
char ci = s[(i + k) % L];
char cj = s[(j + k) % L];
if (ci == cj) {
k++; // 字符相等,继续比较下一个
} else {
// 淘汰较大的那个起始位置
if (ci > cj) {
i += k + 1;
} else {
j += k + 1;
}
// 重置比较长度
k = 0;
// 避免i和j重合
if (i == j) {
j++;
}
}
}
// 最小起始下标为i和j中的较小值
return min(i, j);
}
int main() {
int L;
cin >> L;
cin.ignore(); // 忽略L后的换行符
// 读取字符串(可能跨多行,忽略换行符)
string S;
char ch;
while (S.size() < L && cin.get(ch)) {
if (ch != '\n') { // 跳过换行符,只保留有效字符
S += ch;
}
}
// 计算最小起始下标(0开始),即为口令
int password = minimalRepresentation(S);
cout << password << endl;
return 0;
}
翻译
在开发计算机软件时,计算机科学家和工程师研究软件设计的各个领域和技术,例如在特定程序中使用的最佳编程语言和算法类型,如何高效地存储和检索信息,以及某些软件 - 计算机组合的计算限制。软件设计师在开发程序时必须考虑许多因素。通常,为了软件的整体性能,必须牺牲某一领域的程序性能。例如,由于计算机的内存有限,软件设计师必须限制程序中包含的功能数量,以确保其所需内存不超过设计目标系统所能提供的内存。
软件工程是软件开发的一个领域,计算机科学家和工程师在其中研究能够高效开发正确、可靠和健壮的计算机程序的方法和工具。该分支的研究涵盖软件生命周期的所有阶段,从正式的问题规格说明开始,进而到解决方案的设计、作为程序的实现、程序测试和程序维护。软件工程人员开发软件工具以及称为编程环境的工具集,以改进开发流程。例如,这些工具可以帮助管理由程序员团队编写的大型程序的众多组件。
计算机架构是对新计算机系统的设计与分析。计算机架构师研究如何通过提升速度、存储容量和可靠性,以及降低成本和功耗来改进计算机。他们开发软硬件模型来分析现有和拟议的计算机设计的性能,并用这些分析指导新计算机的开发。由于模型的准确性取决于计算机电路的设计,他们常参与新计算机的工程实现。许多架构师致力于开发适用于特定应用(如图像处理、信号处理或机械系统控制)的专用计算机。针对特定任务优化计算机架构,往往能带来更高性能、更低成本,或两者兼得。
打卡
