有很多题目需要细心考虑过程中是否可能存在递推关系,如果能找到这样的递推关系,就能事时间复杂度下降不少。例如就这一类涉及序列的题目来说,假如序列的每一位所需要的计算的值都可以通过该位左右两侧的结果计算得到,那么就可以考虑所谓的“左右两侧的结果”是否能通过递推进行预处理来得到,这样在后面的使用汇总就可以不必反复求解。
例题:PAT乙级1040 / 甲级1093 有几个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
思路:
直接暴力求解肯定会超时。
换个角度思考问题,对一个确定位置的A来说,以它形成的PAT的个数等于它左边的p的个数乘以它右边T的个数。例如对字符串APPAPT的中间那个A来说,它左边有两个P,右边有一个T,因此这个A能形成的PAT的个数就是2*1=2。于是问题就转换为:对自复查un中的每个A,计算它左边的P的个数和右边的T的个数的乘积,然后把所有A的这个乘积相加就是答案。
代码如下:
#include <iostream> #include <string> using namespace std; int main(){ string str; cin>>str; int leftNum[110000]={0},rightNum=0; int result=0; for(int i=0;i<str.size();i++){ if(i>0){ leftNum[i]=leftNum[i-1];//继承上一个的个数,继续统计 } if(str[i]=='P') leftNum[i]++; } for(int i=str.size()-1;i>0;i--){ if(str[i]=='T'){ rightNum++; }else if(str[i]=='A'){ result=(result+leftNum[i]*rightNum)%1000000007; } } cout<<result; return 0; }