[NOIP2007 提高组] 字符串的展开
题目描述
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于 d-h
或者 4-8
的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为 defgh
和 45678
。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号 -
,减号两侧同为小写字母或同为数字,且按照 ASCII
码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数
p
1
p_1
p1:展开方式。
p
1
=
1
p_1=1
p1=1 时,对于字母子串,填充小写字母;
p
1
=
2
p_1=2
p1=2 时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。
p
1
=
3
p_1=3
p1=3 时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号 *
来填充。
(3) 参数
p
2
p_2
p2:填充字符的重复个数。
p
2
=
k
p_2=k
p2=k 表示同一个字符要连续填充
k
k
k 个。例如,当
p
2
=
3
p_2=3
p2=3 时,子串d-h
应扩展为 deeefffgggh
。减号两边的字符不变。
(4) 参数
p
3
p_3
p3:是否改为逆序:
p
3
=
1
p_3=1
p3=1 表示维持原来顺序,
p
3
=
2
p_3=2
p3=2 表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当
p
1
=
1
p_1=1
p1=1、
p
2
=
2
p_2=2
p2=2、
p
3
=
2
p_3=2
p3=2 时,子串 d-h
应扩展为 dggffeeh
。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:d-e
应输出为 de
,3-4
应输出为 34
。如果减号右边的字符按照 ASCII
码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d
应输出为 d-d
,3-1
应输出为 3-1
。
输入格式
共两行。
第 1 1 1 行为用空格隔开的 3 3 3 个正整数,依次表示参数 p 1 , p 2 , p 3 p_1,p_2,p_3 p1,p2,p3。
第
2
2
2 行为一行字符串,仅由数字、小写字母和减号 -
组成。行首和行末均无空格。
输出格式
共一行,为展开后的字符串。
样例 #1
样例输入 #1
1 2 1
abcs-w1234-9s-4zz
样例输出 #1
abcsttuuvvw1234556677889s-4zz
样例 #2
样例输入 #2
2 3 2
a-d-d
样例输出 #2
aCCCBBBd-d
提示
40 % 40\% 40% 的数据满足:字符串长度不超过 5 5 5。
100 % 100\% 100% 的数据满足: 1 ≤ p 1 ≤ 3 , 1 ≤ p 2 ≤ 8 , 1 ≤ p 3 ≤ 2 1 \le p_1 \le 3,1 \le p_2 \le 8,1 \le p_3 \le 2 1≤p1≤3,1≤p2≤8,1≤p3≤2。字符串长度不超过 100 100 100。
NOIP 2007 提高第二题
1. 特点
这题的难点:繁、杂、模拟东西变量超级多(作者写过最复杂的模拟题之一了)
2、核心思路
我们的准则:减少变量,化繁为简,
- 首先,经过思考可得:p1——我们只要分三类,星号 + 数字和不需要变的字母 + 需要变的字母
- 然后就简单了,判断是不是星号,不是星号,判断是正序还是逆序
3、 遍历
我们的遍历是根据,三个字符之间的关系来定的即 d-d ,每次找三个字符,判断是否满足减号右边的字符恰好是左边字符的后继即可
代码实现部分:
#include<iostream>
using namespace std;
int p1, p2, p3, len;
string st;
char ch1, ch2, ch3;
bool flag = 1; // 是小写字母 ,用途:判断字母需不需要变化
int main(){
cin >> p1 >> p2 >> p3;
cin >> st;
for (int i = 0; i < (int)st.size(); i++){
ch1 = st[i], ch2 = st[i + 1], ch3 = st[i + 2];//取三个字母用来判断关系
if (ch1 >= 'A' && ch1 <= 'Z') flag = !flag;//flag == 0 是大写字母
if (ch2 != '-') cout << ch1;
else if (ch2 == '-'){//是减号才继续
len = ch3 - ch1;//两个字符相差的长度
if ((int)ch1 >= (int)ch3) cout << ch1; //(5)减号右边的字符按照 ASCII 码的顺序小于或等于左边字符
else{
i++;
cout << ch1;
if ((flag && p1 == 1 && (ch1 >= 'a' && ch1 <= 'z')) || (ch1 >= '0' && ch1 <= '9' && (ch3 >= '0' && ch3 <= '9') &&(p1 == 1 || p1 == 2) ) || (!flag && p1 == 2)){ // 是数字且不是要输出星号或者是小写字母且要求输出小写字母或者原本为大写字母且要求输出大写字母
if (p3 == 1){//正序
for (int j = 1; j < len; j++){
for (int k = 0; k < p2; k++) cout << (char)(ch1 + j);//每个输出多少遍
}
}
else{
for (int j = 1; j < len; j++){//逆序
for (int k = 0; k < p2; k++) cout << (char)(ch3 - j);
}
}
}
else if (flag && p1 == 2 && (ch1 >= 'a' && ch1 <= 'z')) {//是小写字母,并且要求输出大写字母
if (p3 == 1){//正序
for (int j = 1; j < len; j++){
for (int k = 0; k < p2; k++) cout << char(ch1 + j - 32);
}
}
else{
for (int j = 1; j < len; j++){//逆序
for (int k = 0; k < p2; k++) cout << char(ch3 - j - 32);
}
}
}
else if (p1 == 3){
for (int j = 1; j < len; j++){
for (int k = 0; k < p2; k++) cout << '*';
}
}
else cout << '-';
}
}
}
return 0;
}
4、总结
简而言之:弄清楚,那些变量,最后需要变化的,以及那些是不变的,把需要变化的变量,分类讨论(即把他们的状态确定下来)
就可以得到结果了!如果能帮到你的话,不妨给个赞呗!