【算法学习笔记】26.扫描维护法 解题报告 SJTU_OJ 1133 数星星

SJTU OJ 1133. 数星星

Description

主任和小伙伴晚上非常无聊,于是带着他的宠物狗出来走走。主任突然发现天空中有一条长度为N的字符串,里面的字符都是大写字母。于是主任和他的小伙伴们开始数星星(STAR)。

主任和他的小伙伴还有宠物狗数星星的数法不太一样。小伙伴是一个很教条的人,他只喜欢有规则的东西。所以他每次会在字符串里面找最早的’S’,然后找’S’之后最早的’T’,然后找’T’之后最早的’A’,最后找’A’之后最早的’R’。也就是找一个位置最靠前的STAR的子序列。每次找到这样一个子序列,小Z就数到一个星星,然后把这个子序列删掉,并继续,直到找不到星星为止。

宠物狗喜欢简单一些的东西。它每次只是随便找S,T,A,R各一个,算一个星星,并把字母删掉。

主任不喜欢删掉星星,所以他每次随便选S,T,A,R各一个,算一个星星。但是主任记忆力很好,相同位置组合的星星主任是不会重复数的。

现在要你来算算主任、他的宠物狗、还有小伙伴分别最多可以数到几个星星。

Input Format

共1行。

第一行:一个字符串S,没有多余字符,最后有换行符。

Output Format

三个整数,用空格隔开,分别是主任、宠物狗和小伙伴数到的星星数。

Sample Input 1

STAR

Sample Output 1

1 1 1

Limits

30% N<=10 60% N<=60 100% N<=1000

题目经过分析之后 其实就是求三个值 (s表示S出现的次数....)

¡1.求s*t*a*r

¡2.求min(s,t,a,r)

¡3.求最多能选出多少子序列”STAR”

前两问非常简单,主要是最后一问比较麻烦。

解法1就是纯粹的模拟法来进行模拟求,主意到最大的子序列个数也不会超过min(s,t,a,r) 所以可以进行遍历某个子序列的s的坐标,然后求得最近的t的坐标,最近的a的坐标,最近的r的坐标

int star[4][N];//0S 1T 2A 3R 第二维的长度表示有该字符的个数,记录的是这些字符的位置

int cur[4]={0};//记录fri使用的光标 

  //四个字符当前走到的光标 如果满足 star[i][cur[i]]<star[j][cur[j]] 对于任意的i<j都成立时 则friend++;
    //Note:最多也只有min个star 所以循环的时候以min为上限
    //最重要的是更新光标 使得能够满足条件 为了方便 设置一个函数来更新
    //模拟法 每次选最初的S 然后依次找出T A R
    for (int i = 0; i < maximum; ++i)
    {
        cur[0]=i;
        if(updateCur(1) && updateCur(2) && updateCur(3)){
            ++fri;
        }else{
            break;//当前的s的位置找不到star子序列接下来的位置肯定也找不到了
        }
    }

//将flag的光标更新至能够使得star[flag-1][cur[flag-1]]<star[flag][cur[flag]]
bool updateCur(int flag){
    //此处的max是所有len的min值, max的含义是最多能用到多少个
    //如果满足条件 也可以根本不更新 但是返回更新成功
    for (; cur[flag] < maximum; ++cur[flag])
        if( star[flag-1][cur[flag-1]]< star[flag][cur[flag]] )
            return true;//更新成功 同时也表示删除了这个字母(?会不会导致 此次s位置没有更新成功但是多删除了一个?)
    return false;
}

此方法看似没错...但是只能20分...暂时还没找到错误之处...留作以后慢慢分析...

第二种方法: 扫描维护法 也是一种在线计算的方法(在线计算的意思是:随时停止输入都能得到之前输入的结果)

这个思路的核心是这样的,若某一次输入之后s<t了,那么至少有一个t是用不到的,这个用不到指的是 根本连ST都组成不了 因为此时的s指的是前面所有输入中s的个数,

那么如果s>t表示当前输入的T一定可以组成ST子串,所以t的个数指的是一定可以组成ST的数量依次类推

如果我们保持s>=t>=a 那么a的个数指的是 一定可以组成STA子串的数量

如果保持s>=t>=a>=r 那么最后的r表示的是一定可以组成STAR的数量 也就是答案

    int s(0),t(0),a(0),r(0);
    for (int i = 0; i < n; ++i)
    {
        switch(sky[i]){
            case ‘S‘:
                s++;break;
            case ‘T‘:
//注意 接下来的所有维护条件里的s t a 都是在此次输入之前的结果 所以如果s>t表示新输入的T一定会用得上
//此处的用得上是相对于之前的S来说的,最终能不能成为完整的子序列还不知道
                if(s>=(t+1))//如果此T是用得上的 那么就记入 注意是一定用得上
                    t++;
                break;//如果此T根本不会组成ST 就不记入
            case ‘A‘:
                if(t>=a+1)
                    a++;//因为可以组成STA
                break;
            case ‘R‘:
                if(a>=r+1)
                    r++;//可以组成STAR
                break;
        }
    }
    fri = r;//最后的r就是答案
时间: 2024-10-13 22:45:53

【算法学习笔记】26.扫描维护法 解题报告 SJTU_OJ 1133 数星星的相关文章

【算法学习笔记】28.枚举法 解题报告 SJTU_OJ 1255 1256 魔戒

1256. 你的魔戒?不,是你的魔戒.加强版 Description 在前往末日火山的途中,佛罗多与他的霍比特人同胞不幸被半兽人抓住了.半兽人要对每个霍比特人进行询问,以找出哪个霍比特人携带了至尊魔戒.每个霍比特人可能会说以下几种话: I have the ring. 我有魔戒. I have not the ring. 我没有魔戒. XXX has the ring. XXX有魔戒.(XXX表示某个霍比特人的名字) XXX has not the ring. XXX没有魔戒. Today is

【算法学习笔记】29.规律题 解题报告 SJTU_OJ 1101 SuperXOR

1101. SuperXOR Description Pangzi recently realized that bitwise XOR operation is just an addition without carries. For example, when computing (1001)_2 XOR (1101)_2, you write down: 1001 + 1101 ------- 0100 You see, everything is like an addition, e

【算法学习笔记】25.贪心法 均分纸牌问题的分析

贪心法: 贪?算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解. 贪心算法不是对所有问题都能得到整体最优解,关键是贪?心策略的选择,选择的贪?策略必须具备?后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关. 太概念化了.总结起来三点: 可行性:必须满足问题的约束 局部最优:当前步骤中所有可行的选择里最佳的局部选择. 不可取消:选择一旦做出,后面的步骤就无法改变. 问题要具有贪心选择性

【算法学习笔记】64. 枚举法 SJTU OJ 1381 畅畅的牙签

枚举法就好了,推理很麻烦,感觉也做不出来. 创造一个结构体,一个是真实的数,一个是花费的牙签数. 构建一位数,两位数,三位数即可. #include <iostream> #include <vector> using namespace std; //从0到9耗费的牙签数 int cost[10]={6,2,5,5,4,5,6,3,7,6}; struct num { int n;//用于计算的数 int c;//耗费的牙签 }; num v[100000]; int main(

【算法学习笔记】61.回溯法 DFS SJTU OJ 1106 sudoku

虽然DLX可以提高效率....但是对于NPC问题也不用太追求效率了,而且还只有一个测试点. 所以 只要DFS不断的填入,直到空格全部被填满:要注意的是DFS中全局变量的更新和恢复. 至于存储的方法,只要考虑每一行每一列每一个小块的不重复即可. #include <iostream> #include <cstring> using namespace std; int cnt = 0 ;//表示剩余的要填的空格的数目 struct point { int x,y; }; point

【算法学习笔记】69. 枚举法 字典序处理 SJTU OJ 1047 The Clocks

我们发现这个题里每一种“移动套餐”用的次数只有0,1,2,3 是有效的,4和0是一样的. 所以我们开一个数组rot[10]来记录这9个套餐分别用了多少次. 字典序的处理和我们的枚举顺序息息相关. 我们从 000000000 到 333333333 来枚举的话,第一个符合条件的结果当然就是所有答案中字典序最小的一个了. 枚举这个排列我们需要用9个for,当然也可以用递归来实现,不过我还是喜欢视觉感比较强烈的9个for.... 在每一种排列下,我们需要通过这些套餐的方案来计算临时结果path. 然后

python基础教程_学习笔记26:好玩的编程

好玩的编程 程序设计的柔术 当大家坐下来并计划应该如何组织程序的时候,对于这个具体的程序,还没有任何的经验.在实现功能的时候,会逐渐地学到对原始设计有用的新知识.不应该无视一路走来所吸取的教训,而应该将它们用于软件的重新设计(或重构)中. 灵活性的实现包括许多方面,下面是其中两个: 原型设计:python最棒的功能之一就是可以快速地编写程序.编写原型程序是更充分地了解问题的一种很好的方法. 配置:灵活性有很多种存在形式.配置的目的就是让程序某部分的改变更简单,对于你和用户来说都是这样. 第三点是

算法学习笔记 最短路

图论中一个经典问题就是求最短路,最为基础和最为经典的算法莫过于 Dijkstra 和 Floyd 算法,一个是贪心算法,一个是动态规划,这也是算法中的两大经典代表.用一个简单图在纸上一步一步演算,也是很好理解的,理解透自己多默写几次即可记住,机试时主要的工作往往就是快速构造邻接矩阵了. 对于平时的练习,一个很厉害的 ACMer  @BenLin_BLY 说:"刷水题可以加快我们编程的速度,做经典则可以让我们触类旁通,初期如果遇见很多编不出,不妨就写伪代码,理思路,在纸上进行整体分析和一步步的演算

带花树算法学习笔记

带花树算法学习笔记 难得yyb写了一个这么正式的标题 Q:为啥要学带花树这种东西啊? A:因为我太菜了,要多学点东西才能不被吊打 Q:为啥要学带花树这种东西啊? A:因为我做自己的专题做不动了,只能先去"预习"ppl的专题了 Q:为啥要学带花树这种东西啊? A:因为可以用来做题啊,比如某WC题目 先推荐一个很皮很皮的带花树讲解: 戳这里嗷 QaQ 言归正传 带花树的算法用来解决一般图的最大匹配问题 说起来,是不是想起来网络流里面的最小路径覆盖? 或者二分图的最大匹配的问题? 的确,带花