LuoguP1098 字符串的展开 题解
作者:互联网
Update
- \(\texttt{2020.9.13}\) 重新排版了一下此题解,并修改了一些措辞,删除了一些已经废掉了的东西和废话。
Content
给定一个字符串 \(s\),和三个参数 \(p_1,p_2,p_3\),求按照题目中的规则扩展之后的字符串。
规则实在无法简要概括,请前往原题题面查看。
数据范围:\(1\leqslant p_1\leqslant 3,1\leqslant p_2\leqslant 8,1\leqslant p_3\leqslant 2\),字符串长度不超过 \(100\)。
Solution
这题其实就是一道纯粹的模拟,而且什么优化都不要就可以 AC。
Part 1 特判
首先,输入完之后,将字符串的长度用一变量储存。接着,先用一个 for 循环来遍历字符串内每一个字符。这就要提到我们程序里第一个,也是最长的一个特判。其中:
- \(i\) 表示字符在字符串中的位置。
- \(a\) 是输入的字符数组。
if(a[i] == '-' && a[i - 1] < a[i + 1] && ((a[i - 1] >= 'a' && a[i + 1] <= 'z') || (a[i - 1] >= '0' && a[i + 1] <= '9')))
是不是看着有点头晕?别着急,咱们一步一个踏实的脚印,仔细分析一下这一段代码。
这段代码其实就是在判断这个字符是否满足展开的条件。你可能有问题了,不需要特判 \(i\) 是不是第一个或最后一个么?其实,字符数组有一个特性,就是在超过字符数组开的范围的时候默认为空(亲测证实当字符数组的位置为负数时也是默认为空)。那么首先要特判的,是这个字符得要是-
才有可能展开,接下来是判断-
前面的字符是不是严格小于后面的字符。后面的四个条件,就是说两个字符是否都是小写字母或数字(注意!因为两个字符都是同一类型且前面的字符严格小于后面的字符,所以,判断完后面的字符小于z
或9
,前面的字符就一定小于z
或9
。同理,判断完前面的字符大于a
或0
,后面的字符就一定大于a
或0
。)。
总结一下,上面的特判就是在做以下的内容:
- 是否是
-
这个字符 - 是否满足前面的字符严格小于后面的字符
- 两个字符是否是同一个类型
第二个特判是在输出的时候(以 \(p_1=2,p_3=1\) 时为例):
for(char j = a[i - 1] + 1; j <= a[i + 1] - 1; ++j)
for(int k = 1; k <= p2; ++k) {
// puts((j >= 'a') && (j <= 'z') && (j > '9') ? "YES" : "NO");
printf("%c", (j >= 'a' && j <= 'z' && j > '9') ? j - 32 : j);
}
以下是对这段代码的解释:
- 因为当 \(p_1=1\) 时,输出小写字母,所以不需要特判左右是不是大写字母。
- 注释的内容是我在中间调试时加上去的。可以把它忽略。
当 \(p_2=2\) 时,如果前后是小写字母,就要将输出的字符改为大写字符,才能输出正确。
Part 2 过程
首先,如果 \(p_1=1\),那么得先判断是倒序输出还是顺序输出。判断完以后,注意!输出展开的部分里没有两端字母,所以,执行语句时,开始结束的两端应该是-
前的字母在字母表中后一个字母(例如,a
的后一个字母应该是b
)和-
后的字母在字母表中前一个字母(例如,z
的前一个字母应该是y
)。这可以用一个 for 循环实现:
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
然后,再将其输出 \(p_2\) 次,这也可以用一个 for 循环来实现:
for(int k = 1; k <= p2; ++k)
\(p_1=2\) 的时候也是同样的道理,只需注意一下特判就行了。
\(p_1=3\) 的时候,将上面的j循环和k循环复制下来,然后输出的内容改为*
就行了。
以上是所有分析的内容,若仍有不懂的地方,可以看以下的代码来加深理解。
Code
1 Final Version\(\small\texttt{ 27ms~/~696.00KB}\)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
int p1, p2, p3;
string a;
int main() {
// freopen("expand.in", "r", stdin);
// freopen("expand.out", "w", stdout);
scanf("%d%d%d", &p1, &p2, &p3);
cin >> a;
int len = a.size();
for(int i = 0; i < len; ++i) {
if(a[i] == '-' && a[i - 1] < a[i + 1] && ((a[i - 1] >= 'a' && a[i - 1] <= 'z' && a[i + 1] >= 'a' && a[i + 1] <= 'z') || (a[i - 1] >= '0' && a[i - 1] <= '9' && a[i + 1] >= '0' && a[i + 1] <= '9'))) {
if(p1 == 1) {
if(p3 == 2)
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("%c", j);
else
for(char j = a[i - 1] + 1; j <= a[i + 1] - 1; ++j)
for(int k = 1; k <= p2; ++k) {
printf("%c", j);
}
} else if(p1 == 2) {
if(p3 == 2)
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("%c", (j >= 'a' && j <= 'z' && j > '9') ? j - 32 : j);
else
for(char j = a[i - 1] + 1; j <= a[i + 1] - 1; ++j)
for(int k = 1; k <= p2; ++k) {
// puts((j >= 'A') && (j <= 'Z') && (j > '9') ? "YES" : "NO");
printf("%c", (j >= 'a' && j <= 'z' && j > '9') ? j - 32 : j);
}
} else if(p1 == 3) {
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("*");
}
}else if(a[i] == '-' && a[i + 1] == a[i - 1] + 1)
printf("%c%c", a[i - 1], a[i + 1]);
else
printf("%c", a[i]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
2 First Version
此为笔者在 2019 年参加的包含此题的模拟赛时的代码,请忽略 \(\mathcal{O}(3)\) 优化(亲测发现不加也能过)。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#pragma GCC optimize(3)
using namespace std;
int p1, p2, p3;
string a;
int main() {
// freopen("expand.in", "r", stdin);
// freopen("expand.out", "w", stdout);
scanf("%d%d%d", &p1, &p2, &p3);
cin >> a;
int len = a.size();
printf("%c", a[0]);
for(int i = 1; i < len - 1; ++i) {
if(a[i] == '-' && a[i - 1] < a[i + 1] && ((a[i - 1] >= 'A' && a[i - 1] <= 'Z' && a[i + 1] >= 'A' && a[i + 1] <= 'Z') || (a[i - 1] >= 'a' && a[i - 1] <= 'z' && a[i + 1] >= 'a' && a[i + 1] <= 'z') || (a[i - 1] >= '0' && a[i - 1] <= '9' && a[i + 1] >= '0' && a[i + 1] <= '9'))) {
if(p1 == 1) {
if(p3 == 2)
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("%c", (j >= 'A' && j <= 'Z' && j > '9') ? j + 32 : j);
else
for(char j = a[i - 1] + 1; j <= a[i + 1] - 1; ++j)
for(int k = 1; k <= p2; ++k) {
// puts((j >= 'A') && (j <= 'Z') && (j > '9') ? "YES" : "NO");
printf("%c", (j >= 'A' && j <= 'Z' && j > '9') ? j + 32 : j);
}
} else if(p1 == 2) {
if(p3 == 2)
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("%c", (j >= 'a' && j <= 'z' && j > '9') ? j - 32 : j);
else
for(char j = a[i - 1] + 1; j <= a[i + 1] - 1; ++j)
for(int k = 1; k <= p2; ++k) {
// puts((j >= 'A') && (j <= 'Z') && (j > '9') ? "YES" : "NO");
printf("%c", (j >= 'a' && j <= 'z' && j > '9') ? j - 32 : j);
}
} else if(p1 == 3) {
for(char j = a[i + 1] - 1; j >= a[i - 1] + 1; --j)
for(int k = 1; k <= p2; ++k)
printf("*");
}
}else if(a[i] == '-' && a[i + 1] == a[i - 1] + 1)
printf("%c%c", a[i - 1], a[i + 1]);
else
printf("%c", a[i]);
}
printf("%c", a[len - 1]);
// fclose(stdin);
// fclose(stdout);
return 0;
}
Conclusion
总的来说,这个题目其实就是一个暴力模拟,不过呢需要注意一些特判和输出的技巧。只要把题目理解了,同类型的题目自然就会做了。
标签:字符,LuoguP1098,int,题解,特判,char,&&,字符串,include 来源: https://www.cnblogs.com/Eason-AC/p/15725311.html