其他分享
首页 > 其他分享> > LuoguP1098 字符串的展开 题解

LuoguP1098 字符串的展开 题解

作者:互联网

Update

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 循环来遍历字符串内每一个字符。这就要提到我们程序里第一个,也是最长的一个特判。其中:

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\) 是不是第一个或最后一个么?其实,字符数组有一个特性,就是在超过字符数组开的范围的时候默认为空(亲测证实当字符数组的位置为负数时也是默认为空)。那么首先要特判的,是这个字符得要是-才有可能展开,接下来是判断-前面的字符是不是严格小于后面的字符。后面的四个条件,就是说两个字符是否都是小写字母或数字(注意!因为两个字符都是同一类型且前面的字符严格小于后面的字符,所以,判断完后面的字符小于z9,前面的字符就一定小于z9。同理,判断完前面的字符大于a0,后面的字符就一定大于a0)。

总结一下,上面的特判就是在做以下的内容:

  1. 是否是-这个字符
  2. 是否满足前面的字符严格小于后面的字符
  3. 两个字符是否是同一个类型

第二个特判是在输出的时候(以 \(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);
							}

以下是对这段代码的解释:

  1. 因为当 \(p_1=1\) 时,输出小写字母,所以不需要特判左右是不是大写字母。
  2. 注释的内容是我在中间调试时加上去的。可以把它忽略。

当 \(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