这是活用递推里面比较经典的一种题型;
若是采用最简单的暴力枚举,则会出现time limited错误。
这道题关键是可以找到递推的思路。对于序列中的每个每个A,若是可以有PAT出现,则一定A的左右都有P和T;若是A左边有a个P,右边有b个T,则能够推出含有该A的PAT有a*b个;因此解法就被分解成如下几个步骤:
1.寻找左边P的个数;
2.寻找右边T的个数;
3.遍历A,进行左右的乘积;
至于P和T个数的保存,咱们能够仿照迪杰斯特拉算法中的distance数组来进行构造;
首先对于保存P的数组,进行输入数组的遍历,每一次从前一位继承P的数目,若是该位为P,则数目加一,从而构成一个保存的P的数组,其中index索引处的值表明输入序列index位的左边P的个数;
相关代码以下:算法
int len=strlen(str); for(int i=0;i<len;i++){ if(i>0){ leftNumP[i]=leftNumP[i-1]; } if(str[i]=='P'){ leftNumP[i]++; } }
对于T,则不必构建数组,由于能够在计数的同时从后往前遍历,这样就将第三第四步结合在了一块儿;
相关代码以下;数组
nt ans=0,rightNumT=0; for(int i=len-1;i>=0;i--){ if(str[i]=='T'){ rightNumT++; }else if(str[i]=='A'){ ans=(ans+leftNumP[i]*rightNumT)%MOD; } }
从而能够经过一次遍历完成后两步的任务;
整体代码以下所示:code
#include<cstdio> #include<stdlib.h> #include<cstring> const int MAXN=100010; const int MOD=1000000007; char str[MAXN]; int leftNumP[MAXN]={0}; int main(){ scanf("%s",str); int len=strlen(str); for(int i=0;i<len;i++){ if(i>0){ leftNumP[i]=leftNumP[i-1]; } if(str[i]=='P'){ leftNumP[i]++; } } int ans=0,rightNumT=0; for(int i=len-1;i>=0;i--){ if(str[i]=='T'){ rightNumT++; }else if(str[i]=='A'){ ans=(ans+leftNumP[i]*rightNumT)%MOD; } } printf("%d\n",ans); system("pause"); return 0; }