题目描述
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确” 大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确 ”的条件是:
- 字符串中必须仅有 P、A、T这三种字符,不可以包含其它字符;
- 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
- 如果 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字符指针没有初始化的问题,于是后面干脆改用数组,才顺利通过。