题解:洛谷 P1098 [NOIP 2007 提高组] 字符串的展开

【题目来源】

洛谷:[P1098 NOIP 2007 提高组] 字符串的展开 - 洛谷 (luogu.com.cn)

【题目描述】

在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于 d-h 或者 4-8 的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为 defgh45678。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:

(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号 - ,减号两侧同为小写字母或同为数字,且按照 ASCII 码的顺序,减号右边的字符严格大于左边的字符。

(2) 参数 \(p_1\):展开方式。\(p_1=1\) 时,对于字母子串,填充小写字母;\(p_1=2\) 时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。\(p_1=3\) 时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号 * 来填充。

(3) 参数 \(p_2\):填充字符的重复个数。\(p_2=k\) 表示同一个字符要连续填充 \(k\) 个。例如,当 \(p_2=3\) 时,子串 d-h 应扩展为 deeefffgggh。减号两边的字符不变。

(4) 参数 \(p_3\):是否改为逆序:\(p_3=1\) 表示维持原来顺序,\(p_3=2\) 表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当 \(p_1=1\)\(p_2=2\)\(p_3=2\) 时,子串 d-h 应扩展为 dggffeeh

(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:d-e 应输出为 de3-4 应输出为 34。如果减号右边的字符按照 ASCII 码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d 应输出为 d-d3-1 应输出为 3-1

【输入】

共两行。

\(1\) 行为用空格隔开的 \(3\) 个正整数,依次表示参数 \(p_1,p_2,p_3\)

\(2\) 行为一行字符串,仅由数字、小写字母和减号 - 组成。行首和行末均无空格。

【输出】

共一行,为展开后的字符串。

【输入样例】

1 2 1
abcs-w1234-9s-4zz

【输出样例】

abcsttuuvvw1234556677889s-4zz

【算法标签】

《洛谷 P1098 字符串的展开》 #模拟# #字符串# #NOIP提高组# #2007#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int p1, p2, p3; // p1: 控制大小写或替换为*;p2: 控制填充字符的重复次数;p3: 控制填充顺序(正序或逆序)
string s;       // 输入的字符串

// 判断两个字符是否同时为数字或同时为字母
bool judge(char a, char b)
{
    if (isdigit(a) && isdigit(b))  // 如果a和b都是数字
        return true;
    else if (isalpha(a) && isalpha(b))  // 如果a和b都是字母
        return true;
    return false; // 否则返回false
}

// 扩展填充函数,根据p1、p2、p3的规则填充字符
void exp(char a, char b)
{
    if (p3 == 1) { // 如果p3为1,按正序填充
        for (char i = a + 1; i < b; i++) 
		{ // 从a的下一个字符到b的前一个字符
            for (int j = 0; j < p2; j++) 
			{ // 重复p2次
                if (p1 == 1) printf("%c", tolower(i)); // p1为1,输出小写字母
                else if (p1 == 2) printf("%c", toupper(i)); // p1为2,输出大写字母
                else printf("*"); // p1为3,输出*
            }
        }
    } 
	else 
	{ // 如果p3为2,按逆序填充
        for (char i = b - 1; i > a; i--) 
		{ // 从b的前一个字符到a的下一个字符
            for (int j = 0; j < p2; j++) 
			{ // 重复p2次
                if (p1 == 1) printf("%c", tolower(i)); // p1为1,输出小写字母
                else if (p1 == 2) printf("%c", toupper(i)); // p1为2,输出大写字母
                else printf("*"); // p1为3,输出*
            }
        }
    }
}

int main()
{
    cin >> p1 >> p2 >> p3 >> s; // 输入p1、p2、p3和字符串s
    for (int i = 0; i < s.size(); i++) 
	{ // 遍历字符串s
        if (s[i] == '-') 
		{ // 如果当前字符是'-'
            if (s[i + 1] - s[i - 1] == 1) 
			{ // 如果'-'前后的字符是连续的(如a-b)
                continue; // 跳过,不处理
            } 
			else if (s[i + 1] <= s[i - 1]) 
			{ // 如果'-'后的字符小于等于前面的字符(如b-a或a-a)
                cout << s[i]; // 直接输出'-'
                continue;
            } 
			else if (judge(s[i - 1], s[i + 1])) 
			{ // 如果'-'前后的字符同时为数字或字母
                exp(s[i - 1], s[i + 1]); // 调用exp函数进行填充
                continue;
            }
        }
        cout << s[i]; // 输出当前字符
    }
    return 0;
}

【运行结果】

1 2 1
abcs-w1234-9s-4zz
abcsttuuvvw1234556677889s-4zz
posted @ 2026-02-17 08:24  团爸讲算法  阅读(1)  评论(0)    收藏  举报