题目
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
- 字符串中必须仅有
P
、A
、T
这三种字符,不可以包含其它字符; - 任意形如
xPATx
的字符串都可以获得“答案正确”,其中x
或者是空字符串,或者是仅由字母A
组成的字符串; - 如果
aPbTc
是正确的,那么aPbATca
也是正确的,其中a
、b
、c
均或者是空字符串,或者是仅由字母A
组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES
,否则输出 NO
。
输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
题意解析
条件1和条件2规定了一个基本的可通过的字符串的形式:xPATx
,基本形式很容易理解,就是P
和T
中间有一个A
,而两侧的A
数量相等,这个数量可以是0个。
而条件3则是补充说明了可通过的其他形式,该其他形式是由某个正确形式推出来的,同时给出了推出该形式的变式方法。由这个变式方法可以不断推出其他形式。
方法:
明确第一点: 变式的递推过程总是不涉及P
和T
的变化,所以,P和T是有且仅有一个的,而且中间至少都含有一个A。
变化: P
和T
之间的A
的数量加1,将左侧的所有A
复制一份到右侧。由此可知,左侧A
也是始终不变化的。所有变式都是由条件2中的基本型推导而来,由条件2可知,最初的形式,左右两侧A数量一致,中间只有一个A。所以,根据中间的A数量来判断,进行了几次变化,每变化一次,右侧都会比左侧多一倍的A数量。由此我们可以推出一个通式:即,左侧A数*中间A数=右侧A数。
可以通过的字符串的通式:
AC代码
- 顺序判断各个成立条件,全部满足则输出正确
#include<stdio.h>
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)//进行n轮输入
{
int ctP=0, //'P'的个数
ctA_pre=0,//在'P'之前的'A'的个数
ctA_mid=0,//在'P'和'T'之间的'A'的个数
ctA_rear=0, //在'T'之后的'A'的个数
ctT=0, //'T'的个数
flag=1; //每层检测出现不符合规则时标记为0
char str[101];//每行输入的字符串
scanf(" %s",str);
for(char *p=str;*p!='\0';p++){//逐一判断单个字符
if(*p=='P'){//计数:P的数量
ctP++;
}
else if(*p=='A'){//计数:A的数量
if(ctP==0&&ctT==0){//左侧A
ctA_pre++;
}
else if(ctP==1&&ctT==0){//中间A
ctA_mid++;
}
else if(ctP==1&&ctT==1){//右侧A
ctA_rear++;A
}
}
else if(*p=='T'){//计数:T
ctT++;
}
else{//非法字符标记错误,退出循环
flag=0;
break;
}
}
if(ctP!=1||ctT!=1||ctA_mid<1){//P,T数量应为1,中间A数量应大于1,否则标记错误
flag=0;
}
if(flag){//前述条件满足的情况下,判断通式是否满足
if(ctA_pre*ctA_mid!=ctA_rear){//判断通式
flag=0;
}
}
if(flag){//所有条件满足,输出“YES”
printf("YES\n");
}
else{//有条件不满足,输出“NO”
printf("NO\n");
}
}
return 0;
}