題目連結:- P1098 [NOIP2007 提高組] 字串的展開
題目敘述:
[NOIP2007 提高組] 字串的展開
題目描述
在初賽普及組的“閱讀程式寫結果”的問題中,我們曾給出一個字串展開的例子:如果在輸入的字串中,含有類似於 d-h
或者 4-8
的字串,我們就把它當作一種簡寫,輸出時,用連續遞增的字母或數字串替代其中的減號,即,將上面兩個子串分別輸出為 defgh
和 45678
。在本題中,我們透過增加一些引數的設定,使字串的展開更為靈活。具體約定如下:
(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
應輸出為 de
,3-4
應輸出為 34
。如果減號右邊的字元按照 ASCII
碼的順序小於或等於左邊字元,輸出時,要保留中間的減號,例如:d-d
應輸出為 d-d
,3-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==2
,p1==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;
}