大家好啊,这里是Cyber Striver的博客。今天我继续为大家带来PAT乙级的题解。
目录
题目
题解
#include <stdio.h>
int main()
{
int n = 0,i=0;
scanf("%d", &n);
char str[101];
for (; n >0; n--)
{
scanf("%s", str);
int other_char_number = 0;
int P_number = 0, T_number = 0;
int B_A = 0, M_A = 0, A_A = 0;
int p=0,t=0;
for (i = 0; i < 101; i++)
{
if (str[i] == '\0')
break;
if (str[i] != 'P' && str[i] != 'A' && str[i] != 'T')
other_char_number++;
if (str[i] == 'P')
{
p = i;
P_number++;
}
if (str[i] == 'T')
{
t = i;
T_number++;
}
}
if (other_char_number != 0 || P_number != 1 || T_number != 1||(p>t)||(p+1==t))
{ if(n==1)
printf("NO");
else
printf("NO\n");
continue;
}
for (i = 0; i < 101; i++)
{
if (str[i] == 'P')
break;
if (str[i] == 'A')
B_A++;
}
for (i++; i < 101; i++)
{
if (str[i] == 'T')
break;
if (str[i] == 'A')
M_A++;
}
for (i++; i < 101; i++)
{
if (str[i] == '\0')
break;
if (str[i] == 'A')
A_A++;
}
if(n!=1)
{if (B_A * M_A == A_A)
printf("YES\n");
else printf("NO\n");
}
else
{
if (B_A * M_A == A_A)
printf("YES");
else printf("NO");
}
}
return 0;
}
思路
这道题算是我目前做到的最有趣的题目之一了。第一遍开始读题读完之后居然有一种云里雾里的感觉。其实在我看来,这道题难就难在它的题目比较难懂,也就是说这道题非常考验你从题目中挖掘有效信息的能力。既然这道题的题目有点难,那我就带着大家来分析分析吧!
条件一:字符串中必须仅有
P
、A
、T
这三种字符,不可以包含其它字符;
这一条,比较简单。意思就是你输入的字符串中只能包含'P'、'A'、'T' 这三种类型的字符,而且每种字符都至少有一个。
条件二:任意形如
xPATx
的字符串都可以获得“答案正确”,其中x
或者是空字符串,或者是仅由字母A
组成的字符串;
这一条比较重要。其暗含了以下2个条件:
①P和T的数量恒为1,并且P始终排在A的前面。
②PT是错误的,PT之间至少有一个A。
③【特别注意】:这里的前后x是相等的一个字符串。例如:APATAA就是错误的。
条件三:如果
aPbTc
是正确的,那么aPbATca
也是正确的,其中a
、b
、c
均或者是空字符串,或者是仅由字母A
组成的字符串。
这则条件更是让人很迷惑了。但是也是最有趣的部分,因为它把结果从特殊推向了一般。
先说说我的思路,在我只看见前两个条件的时候,我还在幻想着是否能够通过某些特例来写程序从而推进到一般的情况。但是当我看见第三个条件的时候,我就打消了我这个念头,因为我发现,正确答案太多太多了,如果要穷举的话几乎不可能——一定有背后的秘密条件!
还记得我在前两个条件中始终在发现这些字符的数量吗?平时偶尔的一想,最终居然成了我解出这道题的关键!
关键就是:(P之前A的个数)*(PT之间A的个数)=T之后A的个数。
而且我们可以用条件三来验证这个关键条件:
N(x)为字符串x中A的个数。
若aPbTc:N(a)*N(b)=N(c)成立
那么aPbATca:N(a)*[N(b)+1]=N(c)+N(a)一定成立。
接下来我将通过我的代码来描述。
int n = 0,i=0;
scanf("%d", &n);
char str[101];
for (; n >0; n--)
{
scanf("%s", str);
int other_char_number = 0;
int P_number = 0, T_number = 0;
int B_A = 0, M_A = 0, A_A = 0;
int p=0,t=0;
首先是这一块:解释下我的这些命名的意义:
other_char_number:PAT三种字符外的字符的数量。
P_number:P字符的数量。 T_number:T字符的数量。
B_A:P字符之前的A的个数。 M_A:P、T字符之间A的个数。 A_A:T字符之后的A的个数
p=字符P的位置。 t=字符T的位置。
第一部分:
for (i = 0; i < 101; i++)
{
if (str[i] == '\0')
break;
if (str[i] != 'P' && str[i] != 'A' && str[i] != 'T')
other_char_number++;
if (str[i] == 'P')
{
p = i;
P_number++;
}
if (str[i] == 'T')
{
t = i;
T_number++;
}
}
if (other_char_number != 0 || P_number != 1 || T_number != 1||(p>t)||(p+1==t))
{ if(n==1)
printf("NO"); //这里分n==1和n!1的情况是因为题目要求最后一个
else //输出不能换行。
printf("NO\n");
continue;
}
遍历字符串:
①检查是否有非PAT字符。
②检查是否有PT字符,并且是否P排在T前面。
③PT不能紧挨,中间至少有一个A。(只要验证PT的位置不是紧挨即可,因为若①成立,则PT之间的字符只有A)。
for (i = 0; i < 101; i++)
{
if (str[i] == 'P')
break;
if (str[i] == 'A')
B_A++;
}
for (i++; i < 101; i++)
{
if (str[i] == 'T')
break;
if (str[i] == 'A')
M_A++;
}
for (i++; i < 101; i++)
{
if (str[i] == '\0')
break;
if (str[i] == 'A')
A_A++;
}
遍历字符串:分别求出P之前的A的个数,PT之间A的个数,T之后A的个数。
if(n!=1)
{if (B_A * M_A == A_A)
printf("YES\n");
else printf("NO\n"); //同样兼顾最后一次输出不换行的要求
}
else
{
if (B_A * M_A == A_A)
printf("YES");
else printf("NO");
}
}
最后一部分:实现关键条件判断。
经验总结
1)这种题目很难懂的题目一定要静下心来仔细分析题目的条件。
2)数学思维很重要!如果没有找到关键条件那个数学公式,我很难想到还有什么方法可以通过。
3)明白了一个字符数组居然可以反复读写字符串,我一直以为只能写一次就不能再写了。
4)继续加油!
本次博客到这里就结束了,如果你觉得我的文章还不错的话,请给我多多点赞评论哦!