2月26-第三次机试课记录

字符处理

  • 多组输入,看清题目

总结和关键

  • 预处理的几种用法
    • 区间和(计算下标i到j的和):使用前缀数组, sum[i, j]=A[j] - A[i - 1];
    • 字符子串使用kmp的next数组
    • 字符子序列使用序列自动机,既一个二维数组next【n】【26】,n为长度,26为26个字母,数组的意义是下标为i的字符其对于最近的26个字母下标(1.初始化从后向前初始化,这个可以从相邻的字母比较得出,2.下标从1开始,区分于0表示没有字母,3.区分子串和子序列)
  • 字符串hash的使用,以及在这个前提下,字符串切割可以转换成为前缀和的处理,字符串循环同构可以转换成2*长数组的处理
  • kmp的书写
  • 单调队列和栈的维护,以及结合题目使用,两个都与最值相关

题号

  • PIPIOJ 1026 a+b问题(根据题意模拟)

  • PIPIOJ 1343 PIPI的字符串问题Ⅰ(序列自动机)

  • PIPIOJ 1039 重复子序列问题(序列自动机)

  • PIPIOJ 1344 PIPI的字符串问题Ⅱ(KMP)

  • PIPIOJ 1345 PIPI的字符串问题Ⅲ(字符串HASH)

  • PIPIOJ 1346 PIPI的字符串问题Ⅳ(字符串HASH)

  • PIPIOJ 1347 PIPI的序列问题Ⅰ(单调队列)

  • PIPIOJ 1351 小鱼比可爱Ⅱ(单调栈)

  • PIPIOJ 1034 字典序最小的子序列(作为作业)

  • PIPIOJ 1348 PIPI的序列问题Ⅱ(作为作业)

思路与技巧

  • 1343

    • 对于子序列问题使用序列自动机,初始化从后向前,下标从1开始,从而是没有字母为0,不会混淆
  • 1039

    • 同样上题
    • 但是需要注意问题分解为多个串与母串的比较
    • 这题有个坑是多组输入
  • 1344

    • 使用kmp(注意初值-1等等)

    • 与上题的区别除了在子串和子序列上,还有就是对于问题的分解上,这题同样是两个串比较可以拆分为多个子串和串比较,但是这题需要注意的是,拆分时候,可以利用next数组直接打到初始化的目的。(aaaaa和aa比较,应该是存在4个子串与aa相同,如果没有正确在两次子问题中初始化,会导致出现答案为2的错误答案)

      int kmp(){
      	int i = 0, j = 0;
      	int ans = 0; 
      	
      	while(i < lenS){
      		while(i < lenS && j < lenT){
      			if(j == -1 || s[i] == t[j]){
      				if(j + 1 == lenT){//一次子问题结束
      					ans ++;//记录
      					j = Next[j];//初始化,正好利用kmp的next数组,直接打到目的,区分上一题
      				}else{
      					i ++;
      					j ++;
      				}
      			}else
      				j = Next[j];
      		}
      	}
      	
      	return ans;
      }
      
  • 1345/1346

    • 字符hash,类似将a隐射到1, z到26这样,字符串直接对应一个数字,两个字符的比较直接变成值的比较
    • 利用预处理后,前缀和,快速剪裁出字符比如abcde的cde,直接从A【5】-A【2】*对应的权 就可以得出
    • 1345判断回文串,利用左右两次前缀和
    • 1346判断循环同构,既abababab中有几个abab的循环同构,利用将abab*2,既abababab,这样计算hash值,会自动包含所有的循环同构,比如abab【下标1-4】,baba【下标2-5(两倍的意义就在于可以用这个5)】
    • 几个计算细节
      • 关于hash
        • 计算的值可以比较大,需要使用typedef unsigned long long ull;
        • 考虑使用机制base=2333;而不是10,对应的权使用数组可以简化计算
        • 字符【l,r】=hs[r] - hs[l - 1] * pw[r - l + 1];
        • a对应1而不是0,这样做的意义在于使用字符串对应的hash,a和ab有区别
  • 1347

    • 使用单调队列,需要自己维护,使用rear和head,不需要循环队列,两端均可以插入删除
    • 其次这个限制长度为m,与之前的题目不同就在,这样的话,如果过长,删除最前的数组元素时,需要注意到要保持每个子问题中都是正的,比如:10 7 -9 8,删除10后,7和-9不再成正数,不应该出现这样的前缀了,所以这题用之前思路会很难写
    • 使用前缀和以及单调队列一下就简化了问题
  • 1351

    • 使用单调栈,还是自己维护
    • 需要注意的是从前向后初始化而不是从后向前,这样做是因为需要找到最近的大于
posted @ 2020-02-26 22:55  fabe2ry  阅读(202)  评论(0编辑  收藏  举报