题目链接:PTA 1040 有几个PAT

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;
}

相关文章: