题目链接:PTA 1040 有几个PAT
- 直接暴力会超时。
- 换个角度思考问题,对一个确定位置的 A 来说,以它形成的 PAT 的个数等于它左边 P 的个数乘以它右边T的个数。例如对字符串 APPAPT 的中间那个 A 来说,它左边有两个 P ,右边有一个T,因此这个 A 能形成的 PAT 的个数就是 2 x 1 = 2。于是问题就转换为,对字符串中的每个A,计算它左边 P 的个数与它右边 T 的个数的乘积,然后把所有 A 的这个乘积相加就是答案。
- 那么有没有比较快的获得每一位左边 P 的个数的方法呢?当然有,只需要设定一个数组 leftNumP,记录每一位左边 P 的个数 (含当前位,下同)。 接着从左到右遍历字符串,如果当前位 i 是P,那么leftNumP[i] 就等于 leftNumP[i- 1] 加 1;如果当前位 i 不是P,那么 lefNumP[i] 就等于 leftNumP[i - 1]。于是只需要 O(len) 的时间复杂度就能统计出 leftNumP 数组。
- 以同样的方法可以计算出每一位右边 T 的个数。为了节省代码量,不妨在统计每一位右边 T 的个数的过程中直接计算答案 ans 。具体做法是:定义一个变量 rightNumT,记录当前累计右边 T 的个数。从右往左遍历字符串,如果当前位 i 是 T ,那么令 rightNumT 加1;否则,如果当前位 i 是A,那么令ans 加上 leftNumP[i] 与 rightNumT 的乘积 (注意取模)。这样,当遍历完字符串时,就得到了答案ans。
#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#define INF 0x3f3f3f3f
typedef long long ll;
const int MAXN = 100010;
const int MOD = 1000000007;
int leftNumP[MAXN];
using namespace std;
int main()
{
string s;
cin>>s;
int len = s.length();
for(int i=0;i<len;i++)
{
if(i>0)
leftNumP[i] = leftNumP[i-1];
if(s[i]=='P')
leftNumP[i]++;
}
int ans = 0;
int rightNumT = 0;
for(int i=len-1;i>=1;i--)
{
if(s[i]=='T')
rightNumT++;
else if(s[i]=='A')
ans = (ans + leftNumP[i]*rightNumT) % MOD;
}
printf("%d",ans);
return 0;
}