2 条题解

  • 6
    @ 2024-4-6 22:52:03

    修正一下题目,p=1p=1 是原序输出,p=2p=2 是逆序输出。

    简单模拟题,按照题目意思模拟即可,但是坑点很多。

    以下默认 si=-s_i = \texttt{-}

    • 对于 p=1p=1,直接枚举 si1+1si+11s_{i-1} + 1 \sim s_{i+1} -1,输出小写字母。
    • 对于 p=2p=2,和 p=1p=1 反一下,输出大写字母。
    • 对于 p=3p=3,输出 *\texttt{*}

    每个字符重复输出 p2p2 次。

    如果 p3=2p3=2,则从 si+11si1+1s_{i+1}-1\sim s_{i-1}+1 倒着枚举。

    srds:

    • -\texttt{-} 符号左、右边一端字母,一端数字,应当输出 -\texttt{-}
    • 如果出现类似于 12345-----\texttt{12345-----} 的数据,输出 -\texttt{-}
    • 如果 s0=-s_0 = \texttt{-},输出 -\texttt{-},譬如:---3-4-3-8\texttt{---3-4-3-8}
    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #define rep(i,x,y) for(int i=x;i<=y;i++)
    #define rrep(i,x,y) for(int i=x;i>=y;i--)
    #define pr printf
    #define inf 1e9
    #define lowbit(x) x & (-x)
    
    const int N=1e6+10;
    inline int read() {
    	int s = 0, w = 1;
    	char c = getchar();
    	while (!isdigit(c)) {
    		if (c == '-') w = -1;
    		c = getchar();
    	}
    	while (isdigit(c)) {
    		s = (s << 1) + (s << 3) + (c ^ 48);
    		c = getchar();
    	}
    	return s * w;
    }
    
    int p1,p2,p3;
    string s;
    
    inline void small(char x){//转小写或者不转。
      if(isdigit(x)) cout<<x;
      else if(x >= 'A' && x <= 'Z') cout<<char(x+32);
      else cout<<x;
    }
    
    inline void big(char x){//转大写或者不转。
      if(isdigit(x)) cout<<x;
      else if(x >= 'a' && x <= 'z') cout<<char(x-32);
      else cout<<x;
    }
    
    inline void judge(int sr , int ed){
    /* 分情况讨论。*/
      if(p1==1){
      	if(p3==2)
      	  rrep(i,s[ed]-1,s[sr]+1)
      	    rep(j,1,p2) small(char(i));
    	else
    	  rep(i,s[sr]+1,s[ed]-1)
    	    rep(j,1,p2) small(char(i));
      }
      if(p1==2){
      	if(p3==2)
      	  rrep(i,s[ed]-1,s[sr]+1)
      	    rep(j,1,p2) big(char(i));
    	else
    	  rep(i,s[sr]+1,s[ed]-1)
    	    rep(j,1,p2) big(char(i));  	
      }
      if(p1==3) rep(i,s[sr]+1,s[ed]-1) rep(j,1,p2) pr("*");
    }
    
    signed main() {
      p1=read();p2=read();p3=read();
      cin>>s;
      int len=s.size();
      rep(i,0,len-1){
      	if(s[i]!='-') cout<<s[i];
      	else{
      	  if(isdigit(s[i-1])&&isalpha(s[i+1])) pr("-");
      	  else if(isalpha(s[i-1])&&isdigit(s[i+1])) pr("-");
      	  else if(s[i-1]=='-'||s[i+1]=='-') pr("-");
    	  else if(s[i-1] >= s[i+1]) pr("-");
    	  else if(!isalnum(s[i-1])||!isalnum(s[i+1])) pr("-");
          else judge(i-1,i+1);
    	}
      }
      return 0;
    }
    
    • @ 2025-7-14 14:10:09

      楼燦,终于找到你了!虽然题解一如既往看不懂

  • 1
    @ 2025-7-14 14:16:12

    Be Patient and Slow!!!

    一.题目简介

    1. 同时遇到下面的情况需要做字符串的展开:
      • 在输入的字符串中,出现了减号“-”;
      • 减号两侧同为小写字母或同为数字;
      • 且按照ASCII码的顺序,减号右边的字符严格大于左边的字符。
    2. 共有三个参数:p1,p2,p3。
      • p2:p2=k表示同一个字符要连续填充k个。
      • p3:是否改为逆序:p3=1表示维持原来顺序,p3=2表示采用逆序输出。
      • p1:这个是最复杂的:p1=1时,对于字母子串,填充小写字母;p1=2时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号“*”来填充。

    二.讲思路(多写几个Function思路就清晰了)

    1. 写一个inline void work(int l,int r)函数:
      • work(a,b)就是负责输出s[a]和s[b]之间的展开式;

      • Example:当主串:a-d,p1=1,p2=2,p3=1时,work(0,2)输出"abbccd";

      • 在主函数遍历s时,if(s[i]=='-') work(i-1,i+1); 在这种情况下:s[i]处理了后,那么对于s[i+1]:它的上一个字符s[i]就是'-',并且在work(i-1,i+1)时已经输出s[i+1],所以就直接跳到s[i+2];

      • if(s[i]!='-') 直接输出s[i];#### 真的就这么简单吗?

        其实不然,举个例子 当主串为:a-b-c时,此时参数p已经不重要了,答案始终是:abc。然而,按照我们刚才的思路:

        • i=0: printf(a);
        • i=1: printf(ab);
        • i=2: printf(b);
        • i=3: printf(bc);
        • i=4: printf(c);

        这样答案就成了aabbbcc:输出出现了重复; 解决:* if(s[i]!='-'),输出s[i]后还要标记used[i]=1;表示i号字符已经处理并输出。

        • if(s[i]=='-'),work(i-1,i+1)时就要判断s[i-1]已经处理没有,及如果used[i]=1,就不输出s[i-1];并且work()之后还要标记used[i+1]=1;
      • 还有一点:主函数循环遍历s时是从0~len(=s.size())-1-1,也就是把是s[len-1] (最后一位单独处理): if(!used[len-1]) printf("%c",s[len-1]);因为如果s[len-1-1]!='-',那么s[len-1]就不会被输出。

    现在上主函数代码

    int main(){
    	ios::sync_with_stdio(0);
    	cin>>p1>>p2>>p3>>s;
    	int len=s.size();
    	printf("%c",s[0]);
    	used[0]=1;
    	for(int i=1;i<len-1;i++){
    	    if(s[i]=='-'){
    	    	work(i-1,i+1);
    	    	used[i+1]=1;
    	    	i+=1;continue;
    		}
    		printf("%c",s[i]);
    		used[i]=1;
    	}
    	if(!used[len-1]) printf("%c",s[len-1]);
        return 0;
    }
    
    1. 详解work(int l,int r)函数.
      • 如果s[l],s[r]同为数字或字母:
        • 如果s[l]<s[r]//符合规范,可以展开;
        • 判断s[l]是否已经被处理过,还未被处理过才输出s[l];
        • 如果p1=3,数字和字母都一样:填充'*'即可,并且不用管p3,因为此时逆序和顺序都一样了,考虑写一个inline void fillstar(int a,int b)函数,执行fillstar(int(s[l])+1,int(s[r])-1);
        • 如果p1=1或2,此时就要考虑p3,所以写一个inline void reverse(int a,int b)函数。执行reverse(int(s[l])+1,int(s[r])-1);
        • 输出s[r]并返回;
      • 如果s[l]>=不合规范;
        • 判断s[l]是否已经被处理过,还未被处理过才输出s[l];
        • 输出"-"和s[r]并返回;

    现在上work()函数代码

    inline void work(int l,int r){
    	if(isalpha(s[l])&&isalpha(s[r])||isdigit(s[l])&&isdigit(s[r])){
    		if(s[l]<s[r]){
    			if(!used[l]) printf("%c",s[l]);
    			if(p1==1||p1==2) {reverse(int(s[l])+1,int(s[r])-1);}//reverse函数把两种情况一同解决了
    			if(p1==3) {fillstar(int(s[l])+1,int(s[r])-1);}
    			printf("%c",s[r]);
    			return; 
    		}
    	}
    	if(!used[l]) printf("%c",s[l]);
    	printf("-%c",s[r]);
    }
    

    现在上fillstar()函数代码

    inline void fillstar(int l,int r){//如果p1=3,输出'*'
    	for(int i=l;i<=r;i++)
    		for(int j=1;j<=p2;j++)
    			printf("*");
    }
    

    现在上reverse()函数代码

    inline void reverse(int l,int r){
    	if(p3==1){
    		for(int i=l;i<=r;i++)
    		    for(int j=1;j<=p2;j++)
    				printf("%c",deal(char(i)));//deal函数处理大小字母的情况
    	}
    	if(p3==2){
    		for(int i=r;i>=l;i--)
    			for(int j=1;j<=p2;j++)
    				printf("%c",deal(char(i)));//deal函数处理大小字母的情况
    	}
    }
    

    现在上deal()函数代码

    inline char deal(char x){
    	if(isdigit(x)) return x;//如果是x数字,就直接返回x
    	if(p1==1) return x;//如果p1=1,输出小写字母
    	return x-'a'+'A';//如果p1=2,输出所对应的大写字母
    }
    

    三.完整AC代码(30MS完事)

    #include<bits/stdc++.h>
    using namespace std;
    
    int p1,p2,p3,len;
    string s; 
    bool used[110];
    
    inline char deal(char x){
    	if(isdigit(x)) return x;//如果是x数字,就直接返回x
    	if(p1==1) return x;//如果p1=1,输出小写字母
    	return x-'a'+'A';//如果p1=2,输出所对应的大写字母
    }
    
    inline void reverse(int l,int r){
    	if(p3==1){
    		for(int i=l;i<=r;i++)
    		    for(int j=1;j<=p2;j++)
    				printf("%c",deal(char(i)));//deal函数处理大小字母的情况
    	}
    	if(p3==2){
    		for(int i=r;i>=l;i--)
    			for(int j=1;j<=p2;j++)
    				printf("%c",deal(char(i)));//deal函数处理大小字母的情况
    	}
    }
    
    inline void fillstar(int l,int r){//如果p1=3,输出'*'
    	for(int i=l;i<=r;i++)
    		for(int j=1;j<=p2;j++)
    			printf("*");
    }
    
    inline void work(int l,int r){
    	if(isalpha(s[l])&&isalpha(s[r])||isdigit(s[l])&&isdigit(s[r])){
    		if(s[l]<s[r]){
    			if(!used[l]) printf("%c",s[l]);
    			if(p1==1||p1==2) {reverse(int(s[l])+1,int(s[r])-1);}//reverse函数把两种情况一同解决了
    			if(p1==3) {fillstar(int(s[l])+1,int(s[r])-1);}
    			printf("%c",s[r]);
    			return; 
    		}
    	}
    	if(!used[l]) printf("%c",s[l]);
    	printf("-%c",s[r]);
    }
    
    int main(){
    	ios::sync_with_stdio(0);
    	cin>>p1>>p2>>p3>>s;
    	int len=s.size();
    	printf("%c",s[0]);
    	used[0]=1;
    	for(int i=1;i<len-1;i++){
    	    if(s[i]=='-'){
    	    	work(i-1,i+1);
    	    	used[i+1]=1;
    	    	i+=1;continue;
    		}
    		printf("%c",s[i]);
    		used[i]=1;
    	}
    	if(!used[len-1]) printf("%c",s[len-1]);
        return 0;
    }
    

    四.总结:

    遇到复杂的大模拟类问题时

    1. 先想好共有多少种不同的情况;

    2. 看这几种情况有没有能够合并在一起解决的;

    3. 尽量多写点函数,便于理思路。

      什么,你觉得太长,给你缩短一下(代价就是时间变长):

      
      
    #include <bits/stdc++.h>using namespace std;int p1,p2,p3,i=0,k;char ch[300],be,af,f,j,p;//p用于输出;int main() {scanf("%d%d%d%s",&p1,&p2,&p3,ch);//输入;while(ch[i]){//当ch[i]有值时;be=ch[i-1];af=ch[i+1];f=ch[i];//f存储ch[i],便于判断;if(f=='-'&&af>be&&(be>='0'&&af<='9'||be>='a'&&af<='z')){//意思是ch[i]若为'-',就判断其前后是否满足条件,满足进入循环;for(p3==1?j=be+1:j=af-1; p3==1?j<af:j>be; p3==1?j++:j--){p=j;//j是整形变量,p是字符型变量,这样是将p赋值为ASCII码为j的字符;if(p1==2)//是否大写;p=(p>='a')?p-32:p;//如果是字母就转成大写else if(p1==3) p='*';//是否输出'*'for(k=0; k<p2; k++)//输出p2个printf("%c",p);}}elseprintf("%c",f);//如果ch[i]是非'-'或者其前后不满足条件,就原样输出;i++;//一定要放在后面,不然会出错QAQ;}return 0;}
    

    看了这么久,交个学费不过分吧(点个赞)

    
    
    • 1

    信息

    ID
    185
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    (无)
    递交数
    245
    已通过
    79
    上传者