当前位置: 代码迷 >> 综合 >> 模拟赛2---字符串的展开(expand.cpp)
  详细解决方案

模拟赛2---字符串的展开(expand.cpp)

热度:15   发布时间:2024-02-01 07:12:23.0

1.字符串的展开(expand.cpp)

?______________________________细节勾起来,毕竟要求太多太复杂,看漏了就完蛋_____________________________

题目描述

在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“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)参数p3:是否改为逆序: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 1 行为用空格隔开的 3 3 个正整数,依次表示参数 p 1 , p 2 , p 3 p_1,p_2,p_3 ?。
2 2 行为一行字符串,仅由数字、小写字母和减号“ ? - ”组成。行首和行末均无空格。

输出格式

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

输入样例1

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

输出样例1

abcsttuuvvw1234556677889s-4zz

输入样例2

2 3 2
a-d-d

输出样例2

aCCCBBBd-d

数据范围与提示

40 % 40\% 的数据满足:字符串长度不超过 4 4
100 % 100\% 的数据满足: 1 p 1 3 , 1 p 2 8 , 1 p 3 2 1\leq p1\leq 3,1\leq p2\leq 8,1\leq p3\leq 2 。字符串长度不超过 100 100
NOIP 2007 提高第二题

其实我考完之后是十分崩溃的,我最后两行代码长这样:
80行
80几行哎老天,让第一次打这么多行代码打到肾虚的我AC吧!!!

然后非常愉快、顺利地

WA90
???
然后隔壁班的同学兴冲冲跑来给我看正解
正解最后两行长这样
19行

我*¥&&(…?%(#%#…
然后我非常不要脸的复制了下来
果然这种级别的代码是咱看不懂的,接下来由小女子带领大家重打一遍我非常不要脸地交到了洛谷上面复制了数据才找到错误的地方的87行AC代码

题解部分

敲~明显的一道模拟,我们来好好的捋一捋。
为了方便(其实也没方便到哪儿去),我们字符串的下标从1开始:

scanf("%s",s+1);//s是输入的字符串
l=strlen(s+1);  //l是s的长度

然后,因为s的第一个字符不管字母、数字还是减号都得照原样输出,而且也防止如果第一个字符是减号时后面判断 s [ i ? 1 ] s[i-1] 会越界,所以不管三七二十一,先输出第一个元素。
然后是 i i 2   l 2~l 的循环,判断每个字符,如果不是减号,直接输出就好:

if(s[i]!='-')printf("%c",s[i]);

否则就开始写这个程序最复杂的部分。。。(虽然大部分Ctrl+C再Ctrl+V就可以了)

else work(i);

w o r k work 函数里,我们先来判断一下这个字符串符不符合展开的条件。
展开的条件:减号左右两边都是小写字母或都是数字。

bool f(char c1,char c2){			//c1是减号左边的字符,c2是减号右边的字符if(c1<='9'&&c1>='0')			//如果c1是数字return c2<='9'&&c2>='0';	//判断c2是不是数字,如果是,返回true,否则返回falseif(c1<='z'&&c1>='a')			//如果c1是小写字母return c2<='z'&&c2>='a';	//判断c2是不是小写字母,如果是,返回true,否则返回falsereturn 0;						//判断多个减号连在一起的情况,如果c1是减号,返回false
}

由于接下来的代码只有循环和输出这些没营养的东西,我就不逐个贴了哈~

如果f(s[i-1],s[i+1])返回的是 t r u e true ,那么开始判断s[i+1]<=s[i-1]的特殊情况
判断完特殊情况后就开始与 p 1 p1 p 3 p3 纠缠。

如果 p 1 = 3 p1=3 ,那么不管 p 3 p3 ,反正一串 * 号不管正着输出还是反着输出都一样,输出p2*(s[i+1]-s[i-1]-1)个*就行了。

否则,如果 p 3 p3 是1,并且 p 1 p1 是1,让字符 c c s[i-1]+1开始循环,到s[i-1]-1结束,输出 p 2 p2 c c
如果 p 3 p3 是1,且 p 1 p1 是2,如果减号两端是数字,按上面的方式输出就行了,不用另作处理(我才不会告诉你我那10分就是栽在这儿了),否则从s[i+1]-32-1开始,到s[i-1]-32+1结束,输出 p 2 p2 c c

剩下 p 3 = 2 p3=2 的情况和上面差不多,小朋友要锻炼自己的独立思维能力,自己想吧(其实就是我懒得打字了)

完整代码

懒得打注释了,反正上文都讲过

#include<stdio.h>
#include<string.h>
char s[105];
int p1,p2,p3,l;
bool f(char c1,char c2){if(c1<='9'&&c1>='0')return c2<='9'&&c2>='0';if(c1<='z'&&c1>='a')return c2<='z'&&c2>='a';return 0;
}
bool f1(char c){if(c<='9'&&c>=0)return 1;return 0;
}
void work(int i){if(f(s[i-1],s[i+1])){if(s[i+1]<=s[i-1]){printf("-");return;}if(s[i-1]==s[i+1]-1)return;if(p1==3){for(int k=1;k<s[i+1]-s[i-1];++k){for(int j=1;j<=p2;++j)printf("*");}return;}if(p3==1){if(p1==1){for(char c=s[i-1]+1;c<s[i+1];++c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}if(f1(s[i+1])){for(char c=s[i-1]+1;c<s[i+1];++c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}for(char c=s[i-1]-31;c<s[i+1]-32;++c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}else{if(p1==1){for(char c=s[i+1]-1;c>s[i-1];--c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}if(f1(s[i+1])){for(char c=s[i+1]-1;c>s[i-1];--c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}for(char c=s[i+1]-33;c>s[i-1]-32;--c){for(int j=1;j<=p2;++j)printf("%c",c);}return;}}else printf("-");
}
int main(){scanf("%d%d%d",&p1,&p2,&p3);scanf("%*[^\n]%*c");scanf("%s",s+1);l=strlen(s+1);printf("%c",s[1]);for(int i=2;i<=l;++i){if(s[i]!='-')printf("%c",s[i]);else work(i);}return 0;
}

第一次代码上60行欸~( 可见我有多菜