题解:P16469 [GKS 2013 #A] Read Phone Number
MengTian1120
·
·
题解
前言
本篇题解的解题方法为:模拟。
题目大意
题目还是比较好理解的。
:::info[题目]
你知道如何用英文读出电话号码吗?现在让我来告诉你。
例如,在中国,电话号码是 11 位数字,如:15012233444。有人将号码划分为 3-4-4 的格式,即 150 \ 1223 \ 3444;而有人则将号码划分为 3-3-5 的格式,即 150 \ 122 \ 33444。不同的格式会导致读出这些数字的方式不同:
$150 \ 122 \ 33444$ 读作 `one five zero one double two double three triple four`。
现在问题来了:
给定一个电话号码列表以及划分格式,请输出这些号码的正确读法。
规则:
单个数字只需分开读出。
连续 $2$ 个相同数字使用 `double`。
连续 $3$ 个相同数字使用 `triple`。
连续 $4$ 个相同数字使用 `quadruple`。
连续 $5$ 个相同数字使用 `quintuple`。
连续 $6$ 个相同数字使用 `sextuple`。
连续 $7$ 个相同数字使用 `septuple`。
连续 $8$ 个相同数字使用 `octuple`。
连续 $9$ 个相同数字使用 `nonuple`。
连续 $10$ 个相同数字使用 `decuple`。
连续超过 $10$ 个相同数字则全部分开读出。
:::
## 解题思路
根据题目要求模拟即可,没有什么思维难度,做法也比较好想。
## 代码实现
这里有一个技巧,判断重复字符个数的时候,不用一个一个 `if`,开一个 `string` 数组 $mp$,其中,
$mp_i$ 表示连续 $i$ 个相同数字使用的缩写。
同时,数字对应的英文单词也可以开一个 `string` 数组 $num$,其中
$num_i$ 表示数字 $i$ 对应的英文单词。
:::info[Code]
```cpp
string num[]={"zero","one","two","three","four","five","six","seven","eight","nine"};
string mp[]={"","","double","triple","quadruple","quintuple","sextuple","septuple","octuple","nonuple","decuple"};
```
:::
这道题还有一个难点,就是对字符串的处理。
难点在于如何按照给定的格式对电话号码进行分组,并在每个分组内正确处理连续相同数字的读法。
输入的格式字符串如 `3-4-4`,需要将其解析为若干个数字段。这里采用的方法是在原字符串末尾加上一个 `-`,然后遍历每个字符:
- 遇到数字字符时,累加到当前长度变量 $len$ 中:`len=len*10+(c-'0')`。
- 遇到 `-` 时,表示一个分组结束,此时 $len$ 的值就是该分组的长度。
```cpp
f+='-';//末尾加分号,方便处理最后一段
for(char c:f){
if(c != '-') len=len*10+(c-'0');
else{
//处理长度为 len 的分组
len=0;//一定要记得重置!
}
}
```
对于每个长度为 $len$ 的分组,需要从电话号码字符串 $s$ 中取出对应的 $len$ 个字符进行处理。这里使用变量 $pos$ 记录当前处理到的位置。
在每个分组内,采用双指针的方法统计连续相同数字的个数:
```cpp
for(int i=0;i<len;){
char cur=s[pos+i];
int cnt=1;
//向后统计有多少个连续且相同字符
while(i+cnt<len && s[pos+i + cnt]==cur) cnt++;
//根据 cnt 的值决定如何去读
i+=cnt;//跳过已经处理完的字符
}
```
根据统计出的连续个数 $cnt$,按照题目规则输出:
|$cnt$|读法|
|:-:|:-:|
|$1$|直接读数字|
|$2 \sim 10$|使用 `double` ~ `decuple` + 数字|
|$>10$|单独读出|
超过 $10$ 个相同数字全部单读,这是因为题目给出的特殊读法只支持到 `decuple`。
### AC 代码
```cpp
#include <bits/stdc++.h>
using namespace std;
string num[]={"zero","one","two","three","four","five","six","seven","eight","nine"};
string mp[]={"","","double","triple","quadruple","quintuple","sextuple","septuple","octuple","nonuple","decuple"};
int main(){
int T;
cin>>T;
for(int t=1;t<=T;t++){
string s,f,ans;
cin>>s>>f;
f+='-';
int pos=0,len=0;
for(char c:f){
if(c!='-') len=len*10+(c-'0');
else{
for(int i=0;i<len;){
if(pos+i>=s.size()) break;
char cur=s[pos+i];
int cnt=1;
while(i+cnt<len && pos+i+cnt<s.size() && s[pos+i+cnt]==cur) cnt++;
if(cnt>=2 && cnt<=10){
if(!ans.empty()) ans+=" ";
ans+=mp[cnt]+" "+num[cur-'0'];
}
else{
for(int j=0;j<cnt;j++){
if(!ans.empty()) ans+=" ";
ans+=num[cur-'0'];
}
}
i+=cnt;
}
pos+=len;
len=0;
}
}
cout<<"Case #"<<t<<": "<<ans<<'\n';
}
return 0;
}
```
[record](https://www.luogu.com.cn/record/278275210)
## 后记
这是本蒟蒻的第 $2$ 篇题解,求过。
给个赞再走呗!