HDU 4622 Reincarnation(后缀自动机)

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=4622

【题目大意】

  给出一个长度不超过2000的字符串,有不超过10000个询问,问【L,R】子串中出现的子串数目,相同子串不可重复计数。

【题解】

  考虑到字符串长度只有两千,我们对每个位置往后建立2000个后缀自动机,
  这样子就能分别计算每个位置往后出现的字符串数目并保存,
  对于sam上的一个节点来说,它的匹配长度与失配位置的匹配长度只差就是他们之间的子串,
  所以,我们在建立sam可以同时计算出现的子串数目。

【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=4005;
char s[N];
struct sam{
      int p,q,np,nq,cnt,last,tot,a[N][26],l[N],f[N];
      sam(){tot=cnt=0;last=++cnt;}
      int val(int c){return l[c]-l[f[c]];}
      void init(){
          tot=cnt=0;last=++cnt;
          memset(a,0,sizeof(a));
          memset(l,0,sizeof(l));
          memset(f,0,sizeof(f));
      }
      int val(int c){return l[c]-l[f[c]];}
      void extend(int c){
            p=last;np=last=++cnt;l[np]=l[p]+1;
            while(!a[p][c]&&p)a[p][c]=np,p=f[p];
            if(!p){f[np]=1;tot+=val(np);}
            else{
                  q=a[p][c];
                  if(l[p]+1==l[q]){f[np]=q;tot+=val(np);}
                  else{
                        nq=++cnt;l[nq]=l[p]+1;
                        memcpy(a[nq],a[q],sizeof(a[q]));
                        tot-=val(p)+val(q);
                        f[nq]=f[q]; f[np]=f[q]=nq;
                        tot+=val(p)+val(q)+val(np)+val(nq);
                        while(a[p][c]==q)a[p][c]=nq,p=f[p];
                  }
            }
      }int ans[2005][2005];
      void CalAns(){
          scanf("%s",s+1);
          int len=strlen(s+1);
          for(int i=1;i<=len;i++){
              init();
              for(int j=i;j<=len;j++){
                  extend(s[j]-‘a‘);
                  ans[i][j]=tot;
              }
          }
      }
      void solve(){
          int Q,l,r;
          scanf("%d",&Q);
          while(Q--){
              scanf("%d%d",&l,&r);
              printf("%d\n",ans[l][r]);
          }
      }
}sam;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        sam.CalAns();
        sam.solve();
    }return 0;
}

  

时间: 2025-01-21 17:38:27

HDU 4622 Reincarnation(后缀自动机)的相关文章

HDU 4622 Reincarnation 后缀自动机

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Problem Description Now you are back,and have a task to do:Given you a string s consist of lower-case English letters only,denote f(s) as the number of

hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2138    Accepted Submission(s): 732 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

HDU 4622 Reincarnation Hash解法详解

今天想学字符串hash是怎么弄的.就看到了这题模板题 http://acm.hdu.edu.cn/showproblem.php?pid=4622 刚开始当然不懂啦,然后就上网搜解法.很多都是什么后缀自动机那些.作为小白的我当然不懂啦,更重要的是我想学的是字符串hash这种解法呢?然而有这种解法,但是却都是只有代码,看起来很辛苦.所以这里我把我的理解写上来,当然有错误的话,请各路高手指出来,我也好好学习下~~ 首先介绍一个字符串Hash的优秀映射函数:BKDRHash,这里hash一开始是等于0

HDU 4622 Reincarnation

Reincarnation Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 462264-bit integer IO format: %I64d      Java class name: Main Now you are back,and have a task to do:Given you a string s consist of lower-case E

hdu 4641 K-string(后缀自动机)

题目链接:hdu 4641 K-string 题意: 一开始给你一个字符串S,现在有m个操作. 1 x表示在当前字符串末端添加一个字符x. 2 表示查询当前出现次数超过k次的子串有多少个. 题解: 后缀自动机在线维护right集. 没插入一个字符,就沿着fail跳,如果当前节点大于等于k的就不用再跳了,显然之前的节点肯定已经大于等于k了. 然后一旦有新的节点等于k就记录一下当前新增加的子串个数. 1 #include<cstdio> 2 #include<cstring> 3 #d

hdu 4436 str2int(后缀自动机)

题目链接:hdu 4436 str2int 题意: 给你n个字符串,每个字符串都是由数字构成,现在让你将这n个字符串所有的不重复子串构成的十进制数字加起来mod2012. 题解: 似乎这种不重复的子串问题,用后缀自动机都比较无脑搞. 首先将所有的串连起来,中间插个特殊字符,然后建立后缀自动机. 然后拓扑排序,从跟开始往下dp. sum[v]=Σ(sum[x]*10+cnt[x]*j),其中cnt[x]表示有多少条路径能到x这个节点,转移为cnt[v]=Σcnt[x] (x能转移到v),j为这个节

Good Article Good sentence HDU - 4416 (后缀自动机)

Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 \(n\) 个 \(T\) 串,求出 \(S\) 串中有多少子串没有在任意一个 \(T\) 串中出现过 思路 \(\quad\) 首先可以对 \(S\) 串构建后缀自动机,然后在插入 \(n\) 个 \(T\) 串,每两个串之间用 \(27\) 隔开,然后可以求出这个自动机上每个节点出现的最左位置

字符串(后缀自动机):HDU 4622 Reincarnation

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 3194    Accepted Submission(s): 1184 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

HDU 4622 Reincarnation( 任意区间子串的长度, 后缀数组+RMQ)

题目大意:给你一个字符串,给你N次查询,每次给你一个区间让你求出这个区间里面有多少子串. 解题思路:我们肯定要枚举位置,然后找公共子串然后再去掉重复的,但是他的地址对应的rank不是连续的,如果暴力找的话会n*n会超时. 从这个博客学习到一种方法:首先对整个字符串求一次sa[]以及height[],之后对于任意区间[L, R],遍历一遍sa[],只要起点在[L, R]内的后缀就需要进行统计,类似于1)中的方法,不过有一个地方要特别注意的就是全部的sa[]不一定就是区间内的sa[],这是因为区间内