PAT乙级1003我要通过

题目描述

答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确” 大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。

得到“答案正确 ”的条件是:

  1. 字符串中必须仅有 P、A、T这三种字符,不可以包含其它字符;
  2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
  3. 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。

现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:

每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n ( < 10 ) n (<10) n(<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。

输出格式:

每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。

输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO

才做了三道乙级题目,这个题花的时间比较长,有很多方面的原因:
首先是审题,我开始就没能弄清题目的意思。我的理解是只要含有P、A、T,并且在四个间隔中都可以插入任意数量的A的字符串都视为通过,而忽略的个数方面的要求。其实这个条件3开始就没太细看,导致没看出隐藏条件。
这里引用博主he_yang_的分析,用递推来求得关系式

正确答案中必须仅含有一个P, 一个T,并且P必须在T的前面.
必须包含大于等于一个A

用C(n)表示c的长度, B(n)表示b的长度,A(n)表示a的长度, A1表示a初始长度,
C1表示c初始长度, B1表示b初始长度,从条件2容易知道B1=1, A1=C1, 建立递推式如下:
A(n)=A(1)
C(n)=C(n-1)+A(n)
B(n)=B(n-1)

解上述递推式可以知道:
A(n)=A(1)
C(n)=C(n-1)+A(n)=C1+(n-2)A1+A1=nA1
B(n)=B(n-1)+1=n-1+1=n
=> A(n)*B(n)=C(n)
=>即对于任意一个字符串aPbTc都有:
len(a)*len(b)=len©

下面给出用C语言完成这道题的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
    int sum;
    int pFlag,aFlag,tFlag,Flag;
    char p = 'P';
    char a = 'A';
    char t = 'T';
    char input[101];
    scanf("%d", &sum);  
    for(int i=0;i<sum;i++){
        scanf("%s", input);
        int len = strlen(input);
        //检验是否正确
        //分割字符串
        pFlag = 0;
        aFlag = 0;
        tFlag = 0;
        int a1=0,a2=0,a3=0,i=0; //分别统计三个部分的A的个数
        Flag = 0;
        while(i<len){
            //printf("%c\n", input[i]);
            if(input[i]!=p&&input[i]!=a&&input[i]!=t){ //字符串只能有PAT组成
                Flag = 1;
                break;
            }
            if(input[i]==p){ //字符串只有一个P,且出现P之前T未出现
                if(pFlag!=0||tFlag!=0){
                    Flag = 1;
                    break;
                }else{
                    pFlag = 1;
                }
            }
            if(input[i]==a){
                aFlag = 1;
                if(pFlag==1&&tFlag==0){ //第二段
                    a2++;
                }
                if(pFlag==0){  //第一段
                    a1++;
                }
                if(pFlag==1&&tFlag==1){  //第三段
                    a3++;
                }
            }
            if(input[i]==t){
                if(aFlag==0||pFlag==0){ //出现T时必须出现P和A
                    Flag = 1;
                    break;
                }else{
                    tFlag=1;
                }
            }
            i++;
        }
        //printf("%d %d %d %d\n",Flag, aFlag, pFlag, tFlag);
        if(Flag==1) //说明break了
            printf("NO\n");
        else{
            if(aFlag==1&&pFlag==1&&tFlag==1&&a1*a2==a3) 
                printf("YES\n");
            else printf("NO\n");
        }
    }
}

写代码的时候也出现了问题:
一是读输入时候的问题。这个题的输入是多行,于是我开始就不知道怎么在VS Code的控制台中敲入多行输入,而不会因为敲回车直接运行。后来发现,这种多行输入,其实就是用循环,每读一行,处理,输出结果,再读下一行就行,而不是说要先全部读完再处理输出结果。这样的话,虽然在VS Code的控制台中好像是输入输出穿插出现,与题目描述中输入输出完全分开不同,但其实所需要的就是这样。
二是段错误的问题。我开始没有用数组,而是使用字符指针:

for(int i=0;i<sum;i++){
        char* input;
        scanf("%s", input); //太坑了,之前一直在input前加了&

这也导致我在input前面加不加&这里耽误了好久(估计也是太久没写C的缘故)。解决后就出现段错误(但VS Code运行结果完全正确,不知道是不是PAT严一些)。网上查了下,说段错误一般是数组越界,以及野指针或者使用未初始化的指针。花了好长时间我才确定是input字符指针没有初始化的问题,于是后面干脆改用数组,才顺利通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值