洛谷P1098 [NOIP2007 提高組] 字串的展開

Tomorrowland_D發表於2024-07-28

題目連結:- P1098 [NOIP2007 提高組] 字串的展開

題目敘述:

[NOIP2007 提高組] 字串的展開

題目描述

在初賽普及組的“閱讀程式寫結果”的問題中,我們曾給出一個字串展開的例子:如果在輸入的字串中,含有類似於 d-h 或者 4-8 的字串,我們就把它當作一種簡寫,輸出時,用連續遞增的字母或數字串替代其中的減號,即,將上面兩個子串分別輸出為 defgh45678。在本題中,我們透過增加一些引數的設定,使字串的展開更為靈活。具體約定如下:

(1) 遇到下面的情況需要做字串的展開:在輸入的字串中,出現了減號 - ,減號兩側同為小寫字母或同為數字,且按照 ASCII 碼的順序,減號右邊的字元嚴格大於左邊的字元。

(2) 引數 p1:展開方式。p1=1 時,對於字母子串,填充小寫字母;p1=2 時,對於字母子串,填充大寫字母。這兩種情況下數字子串的填充方式相同。p1=3 時,不論是字母子串還是數字字串,都用與要填充的字母個數相同的星號 * 來填充。

(3) 引數 p2:填充字元的重複個數。p2=k 表示同一個字元要連續填充 k個。例如,當p2=3時,子串d-h 應擴充套件為 deeefffgggh。減號兩邊的字元不變。

(4) 引數 p_3:是否改為逆序:p3=1 表示維持原來順序p3=2 表示採用逆序輸出,注意這時候仍然不包括減號兩端的字元。例如當 p1=1、p2=2、p3=2 時,子串 d-h 應擴充套件為 dggffeeh

(5) 如果減號右邊的字元恰好是左邊字元的後繼,只刪除中間的減號,例如:d-e 應輸出為 de3-4 應輸出為 34。如果減號右邊的字元按照 ASCII 碼的順序小於或等於左邊字元,輸出時,要保留中間的減號,例如:d-d 應輸出為 d-d3-1 應輸出為 3-1

輸入格式

共兩行。

第 1 行為用空格隔開的 3 個正整數,依次表示引數 p1,p2,p3。

第 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% 的資料滿足:字串長度不超過 5。

100% 的資料滿足:1<=p1<=3;1<=p2<=8,1<=p3<=2。字串長度不超過 100。

NOIP 2007 提高第二題

思路

這題看起來似乎比較複雜,我們來細心捋一下這道題的邏輯是怎麼樣的。

首先,我們要搜尋到-,並且-的左右兩邊都要有元素,這樣我們才進行填充,因此,我們在接收一個字串以後,我們只需要遍歷它的第二個元素到倒數第二個元素。

其次,我們觀察到,p2這個數字,只決定了我們填充的每一個字元的個數,因此p2應該與大體分類上無關,只與我們構造我們要填充的字串時有關

再一個就是,p3的值,是決定填充後反不反向的問題,因此,我們可以直接構造正向填充的字串,如果p3==2,我們就反轉一下構造的字串,並插入到原本-所對應的那個位置就行了

庫函式

思路講解完了,我們開始講庫函式,這題使用庫函式能夠大大降低我們寫程式碼的時間,建議大家好好了解庫函式

標頭檔案#include<cctype>中的庫函式

1、toupper(x) 如果x是小寫字母,將其轉換成大寫字母

2、tolower(x) 如果x是大寫字母,將其轉換成小寫字母

3、isalpha(x) 判斷x是否為字母

4、isdigit(x) 判斷x是否為數字

5、islower(x) 判斷x是否為小寫字母

6、isupper(x) 判斷x是否為大寫字母

7、isalnum(x) 判斷x是否為字母或數字

8、ispunct(x) 判斷x是否為標點符號

9、isspace(x) 判斷x是否為空格

標頭檔案#include<string>中的庫函式

1、s.erase(x,y) 表示將字串s從x位置起刪除y個字元

2、s.insert(x,y) 表示將字串y(或字元y)插入到s的x位置處

3、s.push_back(x) 表示在s的末尾插入字元x

4、reverse(s.begin(),s.end()) 將字串s翻轉

建議讀者好好深入瞭解一下string類中提供的成員函式

步驟拆解

首先,我們要輸入一個字串和三個數字,然後遍歷這個字串,從第二個元素直到倒數第二個元素,如果碰見-,並且-的左右兩邊是小寫字母(或數字),並且左邊小寫字母(或數字)
ASCII碼小於右邊的,我們才進行處理。

然後,我們明確一個點,我們需要刪除-位置的這個-,然後插入一個新的字串current,接下來就是我們構造這個新的字串的過程.我們構造current分為三種情況

刪除i位置的-的程式碼為:

			//我們無論填充什麼字元,或是不填充字元,都需要刪掉i這個位置的'-’,所以放在最最前面
			s.erase(i,1);

1. p1==1,我們會填充小寫字母,然後根據p3的值判斷是否需要反轉這個字串current,接下來就是構造current的過程

我們從s[i-1]的下一個字母開始,直到s[i+1]的前一個字母,每個字母迴圈p2次,並且都是小寫字母,程式碼如下:

string current;
//構造中間需要填充的那個字串
for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
				char a=c;
				for(int i=1;i<=p2;i++) current+=a;
}

然後,根據p3的值,判斷我們是否需要進行反轉,程式碼如下:

					//如果p3==2,則需要反轉,否則不需要
					if (p3 == 2)  reverse(current.begin(), current.end());

最後,我們在i的這個位置插入字串即可

					//在i的這個位置插入字串
					s.insert(i, current);

做完了p1==1的步驟,p1==2p1==3就迎刃而解了,只需要改變字元a的值,就可以了

2. p1==2的情況

				else if (p1 == 2) {
					string current;
					for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
						char a = toupper(c);
						for (int i = 1; i <= p2; i++) current += a;
					}
					if (p3 == 2)	reverse(current.begin(), current.end());
					s.insert(i, current);
				}

3. p1==3的情況

				else if (p1 == 3) {
					string current;
					for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
						char a = '*';
						for (int i = 1; i <= p2; i++) current += a;
					}
					if (p3 == 2) reverse(current.begin(), current.end());
					s.insert(i, current);
				}

最後,我們直接輸出這個修改後的字串就可以了

最終程式碼

#include<iostream>
#include<cctype>
#include<algorithm>
using namespace std;
int main()
{
	int p1, p2, p3;
	cin >> p1 >> p2 >> p3;
	string s; cin >> s;
	//從第二個元素開始,遍歷到倒數第二個元素結束,因為開頭和結尾的 '-'不需要管
	for (int i = 1; i < s.size() - 1; i++) {
		//只有當-號左右是字元(或數字),並且左邊小於右邊時,我們才處理
		if (s[i] == '-' && ((islower(s[i - 1]) && islower(s[i + 1]) && s[i - 1] < s[i + 1]) || (isdigit(s[i - 1]) && isdigit(s[i + 1]) && s[i - 1] < s[i + 1]))) {
			//我們無論填充什麼字元,或是不填充字元,都需要刪掉i這個位置的'-’,所以放在最最前面
			s.erase(i,1);
			//填充小寫字母
				if (p1 == 1) {
					string current;
					//構造中間需要填充的那個字串
					for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
						char a=c;
						for(int i=1;i<=p2;i++) current+=a;
					}
					//如果p3==2,則需要反轉,否則不需要
					if (p3 == 2)  reverse(current.begin(), current.end());
					//在i的這個位置插入字串
					s.insert(i, current);
				}
				else if (p1 == 2) {
					string current;
					for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
						char a = toupper(c);
						for (int i = 1; i <= p2; i++) current += a;
					}
					if (p3 == 2)	reverse(current.begin(), current.end());
					s.insert(i, current);
				}
				else if (p1 == 3) {
					string current;
					for (char c = s[i - 1] + 1; c <= s[i] - 1; c++) {
						char a = '*';
						for (int i = 1; i <= p2; i++) current += a;
					}
					if (p3 == 2) reverse(current.begin(), current.end());
					s.insert(i, current);
				}
		}
	}
	cout << s << endl;
	return 0;

}

相關文章