代码
#include <iostream>
using namespace std;
int main() {
string s;
cin>>s;
int len = s.length(); //string length
s = " " + s;
int countP[len+2] = {0}; // add: first last
int countT[len+2] = {0}; // add: first last
for(int i=1; i<=len; i++){
if(s.at(i)=='P'){
countP[i] = countP[i-1] + 1;
}
else{
countP[i] = countP[i-1];
}
}
for(int i=len; i>0; i--){
if(s.at(i)=='T'){
countT[i] = countT[i+1] + 1;
}
else{
countT[i] = countT[i+1];
}
}
long long int ans = 0;
for(int i=1; i<=len; i++){
if(s.at(i)=='A'){
ans += countP[i] * countT[i];
ans %= 1000000007;
}
}
cout<<ans<<endl;
return 0;
}
注解
1、直接思路:从头到尾找P,找到一个P后,往后找A,找到一个A后,再往后找T。把所有找到的情况找出来即可。穷举肯定会超时。稍微变通一下,能不能找出每个P字符后面A的数量,每个A后面P的数量,存在数组里?看似可行,但确定P后面A的位置是至关重要的,因为不知道A的位置,就无法确定A后面T的具体数量。
2、转换思路!把刚才的以P为中心,转换成以A为中心。也就是从头到尾遍历找A,找到A后,看看A前面有多少P,后面有多少T,相乘起来就是结果了!这样就解决了刚才说的定位的问题,因为从头到尾遍历找A是容易的。
3、在具体实现时,为了保持一致,我们令字符串位置从1开始,因此手动增加了s.at(0)=’ ',也就是在0位置填了个空格。这样就使得下面这块代码可以保持优雅的一致性了。与此同时,我们开辟的countP和countT数组,也就是用来存某个A前面P数量和后面T数量的数组,也要多开2个单元,即0和last,否则会造成数组越界。如果不这样添加2个单元,开头结尾要单独处理,代码不优雅。
for(int i=1; i<=len; i++){
if(s.at(i)=='P'){
countP[i] = countP[i-1] + 1;
}
else{
countP[i] = countP[i-1];
}
}
for(int i=len; i>0; i--){
if(s.at(i)=='T'){
countT[i] = countT[i+1] + 1;
}
else{
countT[i] = countT[i+1];
}
}
4、最后就是计算结果了,需要注意的是ans的类型,因为可能数量很大,建议用long long int存储。另外,每一步处理完毕后都求一个余数,也能避免数字过大溢出。
long long int ans = 0;
for(int i=1; i<=len; i++){
if(s.at(i)=='A'){
ans += countP[i] * countT[i];
ans %= 1000000007;
}
}