乙级1003
这题和HOJ3788一样,故把那边的sample也拿过来:
题意好理解,就对条件3解释一下:
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
就相当于是先对aPbATca进行操作成aPbTc,这一个新的字符串再对条件1、2、3判断,对于这时候的条件3,aPbTc又是一个新的“aPbATca”,所以在条件3的操作方法一样
先介绍一下自己头次看到这题的想法,纯暴力模拟原题
先排除其它情况
1.如果有PAT之外的字
2.如果P、T出现2次以上或者1次都没出现+没有A
3.如果T前面不是A(判断P后面是不是A可能会有数组溢出的危险)
4.字符串长度不足3的
条件1,直接强行各元素一一对应就行
条件2,xPATx,也就是P左边的A和T右边的A数量一样即可
条件3,先拿出aPbATca,要找到a,bA,ca的位置,这时候我们就有了分开来的这三个组合,将它重组成aPbTc就可以了,然后组成的aPbTc再进行条件1、2、3的判断
纯模拟,对字符串的分解构成操作了很多,代码上有部分注释 还算能理解
模拟题就是要注意如果出什么样例与结果不符了的话,要一步一步慢慢调试,一个分号都不能打错!
AC代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int is1(char *p,int len);
int is2(char *p,int len);
int is3(char *p,int len);
int newlen;
int main(){
int n;
cin>>n;
char pat[102];
while(n--){
scanf("%s",&pat);
int len = strlen(pat);
if(is1(pat,len)||is2(pat,len)||is3(pat,len)){
// printf("is1 = %d\n",is1(pat,len));
// printf("is2 = %d\n",is2(pat,len));
// printf("is3 = %d\n",is3(pat,len));
printf("YES\n");
}else
printf("NO\n");
}
return 0;
}
int is1(char *p,int len){
if(len==3){
if(p[0]=='P'&&p[1]=='A'&&p[2]=='T')
return 1;
}
return 0;
}
int is2(char *p,int len){
int p_pos = 0;
for(int i = 0;i<len;i++){
if(p[i]!='P'&&p[i]!='A'&&p[i]!='T')
return 0;
if(p[i]=='P'&&i+2<len&&p[i+1]=='A'&&p[i+2]=='T'){
p_pos = i;
}
}
if(p_pos+p_pos+3!=len||p_pos == 0)
return 0;
for(int i = 0;i<p_pos;i++){
// printf("p[%d] = %c\n",i,p[i]);
if(p[i]!='A')
return 0;
else{
if(p[i]!=p[i+p_pos+3])
return 0;
}
}
return 1;
}
int is3(char *p,int len){//aPbATca --> aPbTc
int p_pos=-1;
int a_pos=-1;
int t_pos=-1;
int onlyt=0,onlyp=0;
for(int i = 0;i<len;i++){
if(p[i]!='P'&&p[i]!='A'&&p[i]!='T')
return 0;
if(p[i]=='P'){//只有一个P
if(onlyp){
return 0;
}
p_pos = i;
onlyp = 1;
}
if(i>=1&&p[i]=='T'){//只有一个T
if(onlyt){
return 0;
}
t_pos = i;
onlyt = 1;
if(p[i-1]=='A'){//T前面必须是A
a_pos = i-1;
}else return 0; //否则退出没写,一直卡着我的bug位置所在。。
}
}
if(p_pos==-1||a_pos==-1||t_pos==-1)
return 0;
newlen = a_pos+len-p_pos-t_pos;
// printf("p_pos = %d a_pos = %d t_pos = %d newlen = %d\n",p_pos,a_pos,t_pos,newlen);
char aPbTc[newlen];
int pos = 0;
for(pos ; pos <= p_pos ; pos++){//aP
aPbTc[pos] = p[pos];
// printf("p[pos] = %c\n",p[pos]);
}
int lenb = a_pos - p_pos - 1;
// printf("a_pos = %d p_pos = %d lenb = %d \n",a_pos,p_pos,lenb);
for(int i = 0;i<lenb;i++){ //aPbT
aPbTc[pos] = 'A';
pos++;
}
aPbTc[pos++] = 'T';
int lenc = len - p_pos - t_pos - 1;
// printf("lenc = %d\n",lenc);
for(int i = 0;i<lenc;i++){
aPbTc[pos++] = 'A';
}
// for(int i = 0 ;i<newlen;i++){
// printf("%c",aPbTc[i]);
// }
// cout<<endl;
// printf("is1 = %d\n",is1(aPbTc,len));
// printf("is2 = %d\n",is2(aPbTc,len));
if(is1(aPbTc,newlen)||is2(aPbTc,newlen)||is3(aPbTc,newlen)){
return 1;
}
return 0;
}
再讲一下另一个思路:找规律
第一次看的时候看不出规律,第二次看的时候发现了……所以如果遇到一个非常复杂的模拟题可以先放一放,有可能这题会有特殊的规律
针对条件3,首先要明白aPbATca转换成aPbTc后,这个新的字符串也可能还是aPbATca的格式
然后针对这个操作再详细思考一下:
我们从aPbATca转换成aPbTc,实质上是去掉了b+A的一个A,以及c+a的一个a。
如果条件1、2不通过,继续条件3下去,每次都是去掉b+A的一个A,c+a的一个a
去掉最后,肯定是以条件1和条件2为出口出去,那就是说,去掉最后肯定是
xPATx的格式(x=null即条件1)
再将其转换成aPbTc,那就是此时我的B=一个A,a=c
然后往回推成aPbATca,最左边的a不变,每一次b加一个A,c加一个a
推回到原字符串,P和T之间我每加n个A,T后面的字符串内容就是n*a
那就是说 只要我的a*b = c
那它就是一个合格的字符串
AC代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int p_pos = -1;
int t_pos = -1;
int a_pos = -1;
int isright(char *a,int len){//字符串格式确认
int onlyp = 0;
int onlyt = 0;
for(int i = 0;i < len;i++){
if(a[i]!='P'&&a[i]!='A'&&a[i]!='T') return 0;
else{
if(a[i]=='P'){
if(onlyp) return 0;
else {onlyp = 1; p_pos = i;}
}
if(a[i]=='T'){
if(onlyt) return 0;
else {
onlyt = 1;
t_pos = i;
if(a[i-1]=='A') a_pos = i-1;
else return 0;
}
}
}
}
if(!onlyp||!onlyt) return 0;
return 1;
}
int main(){
int n;
cin>>n;
char pat[102];
while(n--){
scanf("%s",&pat);
int len = strlen(pat);
int wellplay = 0;
if(isright(pat,len)){
int lena = p_pos;
int lenb = a_pos - p_pos - 1;
int lenca = len - t_pos - 1;
int lenc = lenca - lena;
if(lenb*lena==lenc){
wellplay = 1;
}
}
if(wellplay)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}