PAT BASIC 1040 有几个PAT
字符串 APPAPT
中包含了两个单词 PAT
,其中第一个 PAT
是第 2 位(P
),第 4 位(A
),第 6 位(T
);第二个 PAT
是第 3 位(P
),第 4 位(A
),第 6 位(T
)。
现给定字符串,问一共可以形成多少个 PAT
?
输入格式:
输入只有一行,包含一个字符串,长度不超过105,只包含 P
、A
、T
三种字母。
输出格式:
在一行中输出给定字符串中包含多少个 PAT
。由于结果可能比较大,只输出对 1000000007 取余数的结果。
输入样例:
APPAPT
输出样例:
2
记录一下自己的思考过程。 一开始O(n^3)的算法自然是第一个排除的,不用测都知道会超时。从P出发去考虑问题,那么只要知道每一个A的位置后面有多少个 T,就只需要对所有的P和A遍历即可,但是O(n^2)也还是不够快,那就要从A去考虑,对于每一个A,可能的排列数量等于 这个A之前P的数量乘上这个A之后T的数量,这样就能得到线性时间的解法。
具体做法可以是 先遍历一次整个字符串,累加得到T的数量。再遍历一次,遇到P时 P++,遇到T时T–,遇到A时计算。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
long long sum=0;
int P=0,A=0,T=0;
char str[100001];
scanf("%s",str);
for(int i=0;i<strlen(str);i++){
if(str[i] == 'T')
T++;
}
for(int i=0;i<strlen(str);i++){
switch(str[i]){
case 'P': P++; break;
case 'A': sum+= (P*T)%1000000007; break; // 计算过程也要取MOD,防止溢出
case 'T': T--; break;
}
}
printf("%d",sum%1000000007);
return 0;
}
自己第一次写的代码,虽然能全AC,但是空间花销很大,有很大优化空间。
大概思路是用数组下标代表字母在字符串中的位置, P_map数组表示某个位置之前P的数量,假如P_map[5]的值为2,说明第五位之前有两个P。 同理T_map数组代表某个位置之后T的数量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int P[100001];
int A[100001];
int T[100001];
int P_map[100001];
int T_map[100001];
int main(){
char ch;
int N = 1;
int nP=0,nA=0,nT=0;
long long sum=0;
while((ch=getchar()) != '\n'){
switch(ch){
case 'P': P[N++]++; nP++; break;
case 'A': A[N++]++; nA++; break;
case 'T': T[N++]++; nT++; break;
}
}
for(int i=1;i<N;i++){
if(T[i] == 1){
T_map[i] = nT-1;
nT--;
}else{
T_map[i] = nT;
}
if(P[N-i]==1){
P_map[N-i] = nP-1;
nP--;
}else{
P_map[N-i] = nP;
}
}
for(int i=1;i<N;i++){
if(A[i] == 1){
sum += P_map[i] * T_map[i];
sum %= 1000000007;
}
}
printf("%d",sum%1000000007);
return 0;
}