PAT-B 1040. 有几个PAT(25)
来源:互联网 发布:淘宝装修店铺视频教程 编辑:程序博客网 时间:2024/05/01 21:43
题目链接在此。
和《算法笔记》内容稍稍不同,下次记录《算法笔记》中的表达。
来了,今天用《算法笔记》的方法实现了一遍,便于理解和总结“打表+递推将时间复杂度减少到O(N)法”的说法(我自己编的……)。
ps:思路一相关是上次的,思路二是《算法笔记》上过来的。
思路
思路1
暴力肯定是要超时的。然而对于一个确定的A来数,以它形成PAT的个数是这个A前面的P的个数以及这个A后面的T的个数的乘积。于是只需要知道所有A之前P的个数以及所有A之后T的个数,然后对于每个A进行前P后T个数乘积累加起来就是答案。
至于如何操作,用numP数组保存每个A之前的P的总个数,即numP[i] = j表示第i个A之前的P的个数为j个;用numT[i]表示第i+1个A(或是输入字符串末端)之前的所有T的个数,用t表示总共有t个A的话,numT[t]-numT[i]求的就是第i个A之后P的个数了。
思路二
思路一真的是真真实实的用’A’来拆分了输入的字符串啊~其实有更加通用的方法,那就是记录每一位左边’P’的个数以及右边’T’的个数(包括自身这一位)。
有了思路一的基础,直接看代码吧。
看完和这一题对照,会发现这个方法无比的好用。之前自己叫它们“用数组表示前n为和”,其实归根结底还是“递推”的思想,现在终于有了更贴切的名字——“打表+递推将时间复杂度减少到O(N)法”。
AC代码
思路一代码
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;char str[100010]; //保存读入的字符串 long long numP[100010] = {0}, p = 0; //numP[i]表示第i个A之前'P'的个数,p为numP下标 long long numT[100010] = {0}, t = 0; //numT[i]表示第i+1个A之前'T'的个数,t为numT下标 long long sum = 0; //保存结果 int main(){ gets(str); int len = strlen(str); int count = 0; //记录A的个数 for(int i = 0; i < len; i++){ if(str[i] == 'P'){ //如果str[i] == 'P' numP[p]++; //第p个A之前的'P'的数目+1 }else if(str[i] == 'T'){ //如果str[i] == 'T' numT[t]++; //第t+1个A之前的'T'的数目+1 }else{ //str[i] == 'A' count++; // A的个数+1 p++; //p+1,开始记录下一个A之前P的个数了 t++; //t+1, 开始记录下一个A之前T的个数了 numP[p] += numP[p-1]; //累加之前的P的个数 numT[t] += numT[t-1]; //累加之前的T的个数 } } for(int j = 0 ; j < count ; j++){ //有多少个A算多少种情况 sum += (numP[j] * (numT[t]-numT[j])); // numP[j]表示第j个A之前有多少个,numT[t]-numT[j] 表示第j个A之后有多少个T } printf("%lld\n",sum%1000000007); return 0;}
思路二代码
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;char str[100010]; //保存输入字符串 int leftP[100010], rightT[100010]; //leftP[i]表示i左侧p的个数,rightT[i]表示i右侧T的个数 int main(){ gets(str); int n = strlen(str); //填充leftP for(int i = 0; i <= n; i++){ if(i > 0){ //不是首位 leftP[i] = leftP[i-1]; //继承上一位的结果 } if(str[i] == 'P'){ //这一位是'P' leftP[i]++; //leftP[i]++ } } //填充rightT for(int i = n-1; i >= 0; i--){ if(i < n-1){ //不是最后一位 rightT[i] = rightT[i+1]; //继承前一位的结果 } if(str[i] == 'T'){ //如果当前位为'T' rightT[i]++; //rightT[i]+1 } } //计算结果并输出 long long sum = 0; //保存结果 for(int i = 0; i < n; i++){ if(str[i] == 'A'){ //如果当前为是A sum += ((leftP[i] * rightT[i])); //则sum加上当前为前面P的个数和后面T的个数的乘积 } } printf("%d\n",sum%1000000007); //记得模完输出 return 0;}
当然,也可以不填充rightT,直接在找rightT的过程中累加答案:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;char str[100010]; //保存输入字符串 int leftP[100010], rightT[100010]; //leftP[i]表示i左侧p的个数,rightT[i]表示i右侧T的个数 int main(){ gets(str); int n = strlen(str); //填充leftP for(int i = 0; i <= n; i++){ if(i > 0){ //不是首位 leftP[i] = leftP[i-1]; //继承上一位的结果 } if(str[i] == 'P'){ //这一位是'P' leftP[i]++; //leftP[i]++ } } int sum = 0; int rightT = 0; for(int i = n-1; i >= 0; i--){ if(str[i] == 'T'){ rightT++; }else if(str[i] == 'A'){ sum = (sum + (rightT*leftP[i]))%1000000007; } } printf("%d\n",sum); return 0;}
0 0
- PAT-B 1040. 有几个PAT(25)
- PAT-B 1040. 有几个PAT(25)
- PAT-B 1040. 有几个PAT
- PAT-B 1040. 有几个PAT
- 【PAT】1040. 有几个PAT(25)
- PAT-1040. 有几个PAT(25)
- 1040. 有几个PAT(25) PAT
- pat:1040. 有几个PAT(25)
- PAT 1040. 有几个PAT(25)
- PAT乙级 有几个PAT(25)
- PAT题目 有几个PAT(25)
- PAT-1030.有几个PAT(25)
- 1040. 有几个PAT(25)PAT乙级&&1093. Count PAT's (25) PAT甲级
- PAT乙级—1040. 有几个PAT(25)-native
- PAT Basic 1040. 有几个PAT(25)
- C++ - PAT - 1040. 有几个PAT(25)
- 1040. 有几个PAT(25)-PAT乙级真题
- PAT乙级.1040. 有几个PAT(25)
- Spring中事务的传播行为
- inverse和cascade的区别,以及一对多添加操作时外键为Null的问题
- RPL(12):RFC6550翻译(12)---目标函数准则
- <操作系统:精髓与设计原理> 进程描述和控制
- 1065
- PAT-B 1040. 有几个PAT(25)
- HDU 5978 To begin or not to begin(概率)
- Vue.js学习系列(三十二)-- Vue.js样式绑定(三)
- 大数据工程师(开发)面试系列(5)
- maven SpringMVC,Spring,Mybatis整合
- BZOJ 2002 分块
- 23种设计模式分析(1):创建型模式
- TypeLite(二)-- 编写生成器
- 第三章 字符串、向量和数组(重点)