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 distinct sub-string of s.
And you have some query,each time you should calculate f(s[l...r]), s[l...r] means the sub-string of s start from l end at r.
 
Input
The first line contains integer T(1<=T<=5), denote the number of the test cases.
For each test cases,the first line contains a string s(1 <= length of s <= 2000).
Denote the length of s by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the number of queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n), denote a query.
 
Output
For each test cases,for each query,print the answer in one line.
 
Sample Input
2
bbaba
5
3 4
2 2
2 5
2 4
1 4
baaba
5
3 3
3 4
1 4
3 5
5 5
 
Sample Output
3
1
7
5
8
1
3
8
5
1

Hint

I won't do anything against hash because I am nice.Of course this problem has a solution that don't rely on hash.

 

题意:

  给你一个母串,

  Q个询问,每次询问你[L,R] 属于这一段中不同子串的个数是多少

题解:

  考虑离线

  把询问缩小,相同L的询问划分为一类

  这样最多就是建立 2000 个后缀自动机了

#include <bits/stdc++.h>
inline long long read(){long long x=,f=;char ch=getchar();while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}return x*f;}
using namespace std; const int N = 2e3+; const long long mod = ; long long now;
int isPlus[N * ],endpos[N * ];int d[N * ];
int tot,slink[*N],trans[*N][],minlen[*N],maxlen[*N],pre;
int newstate(int _maxlen,int _minlen,int* _trans,int _slink){
maxlen[++tot]=_maxlen;minlen[tot]=_minlen;
slink[tot]=_slink;
if(_trans)for(int i=;i<;i++)trans[tot][i]=_trans[i],d[_trans[i]]+=;
return tot;
}
long long update(int u) {
return 1LL*(maxlen[u] - minlen[u] + );
}
int add_char(char ch,int u){
int c=ch-'a',v=u;
int z=newstate(maxlen[u]+,-,NULL,);
isPlus[z] = ;
while(v&&!trans[v][c]){trans[v][c]=z;d[z]+=;v=slink[v];}
if(!v){ minlen[z]=;slink[z]=;now += update(z);return z;}
int x=trans[v][c];
if(maxlen[v]+==maxlen[x]){slink[z]=x;minlen[z]=maxlen[x]+;now += update(z);return z;}
int y=newstate(maxlen[v]+,-,trans[x],slink[x]);
now -= update(x);
slink[z]=slink[x]=y;minlen[x]=minlen[z]=maxlen[y]+;
now += update(x);
while(v&&trans[v][c]==x){trans[v][c]=y;d[x]--,d[y]++;v=slink[v];}
minlen[y]=maxlen[slink[y]]+;
now += update(y);now += update(z);
return z;
}
void init_sam() {
for(int i = ; i <= tot; ++i)
for(int j = ; j < ; ++j) trans[i][j] = ;
pre = tot = ; }
int T,n;
long long ans[];
char a[N * ];
struct ss{int L,R,id;}Q[];
int cmp(ss s1,ss s2) {
if(s1.L == s2.L)return s1.R < s2.R;
return s1.L < s2.L;
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%s%d",a+,&n);
for(int i = ; i <= n; ++i)
scanf("%d%d",&Q[i].L,&Q[i].R),Q[i].id = i;
sort(Q+,Q+n+,cmp);
int l = ,r = ;
for(int i = ; i <= n; ++i) {
if(Q[i].L != Q[i-].L) {init_sam();
l = Q[i].L,r = l-;
now = ;
}
while(r < Q[i].R){
pre = add_char(a[(++r)],pre);
}
ans[Q[i].id] = now;
}
for(int i = ; i <= n; ++i) printf("%lld\n",ans[i]);
}
return ;
}

BKDRHash

#include <cstdio>
#include <cstdlib>
#include <cstring>
typedef unsigned long long int ULL;
//BKDRHash,最优的字符串hash算法。hash一开始是等于0的
const int seed = ; // 31 131 1313 13131 131313 etc..
const int maxn = +;
char str[maxn];
ULL powseed[maxn]; // seed的i次方 爆了也没所谓,sumHash的也爆。用了ULL,爆了也没所谓,也能唯一确定它,无符号
ULL sumHash[maxn]; //前缀hash值
int ans[maxn][maxn]; //ans[L][R]就代表ans,就是区间[L,R]内不同子串的个数
const int MOD = ;
struct StringHash
{
int first[MOD+],num;
ULL EdgeNum[maxn]; // 表明第i条边放的数字(就是sumHash那个数字)
int next[maxn],close[maxn]; //close[i]表示与第i条边所放权值相同的开始的最大位置
//就比如baba,现在枚举长度是2,开始的时候ba,close[1] = 1;表明"ba"开始最大位置是从1开始
//然后枚举到下一个ba的时候,close[1]就要变成3了,开始位置从3开始了
void init ()
{
num = ; memset (first,,sizeof first);
return ;
}
int insert (ULL val,int id) //id是用来改变close[]的
{
int u = val % MOD;
for (int i = first[u]; i ; i = next[i]) //存在边不代表出现过,出现过要用val判断,val才是唯一的,边还是压缩后(%MOD)的呢
{
if (val == EdgeNum[i]) //出现过了
{
int t = close[i]; close[i] = id;//更新最大位置
return t;
}
}
++num; //没出现过的话,就加入图吧
EdgeNum[num] = val; // 这个才是精确的
close[num] = id;
next[num] = first[u];
first[u] = num;
return ;//没出现过
}
}H;
void work ()
{
scanf ("%s",str+);
int lenstr = strlen(str+);
for (int i=;i<=lenstr;++i)
sumHash[i] = sumHash[i-]*seed + str[i];
memset(ans,,sizeof(ans));
for (int L=;L<=lenstr;++L) //暴力枚举子串长度
{
H.init();
for (int i=;i+L-<=lenstr;++i)
{
int pos = H.insert(sumHash[i+L-]-powseed[L]*sumHash[i-],i);
ans[i][i+L-] ++;//ans[L][R]++,自己是一个
ans[pos][i+L-]--;//pos放回0是没用的 }
}
for (int i = lenstr; i>=; i--)
{
for (int j=i;j<=lenstr;j++)
{
ans[i][j] += ans[i+][j]+ans[i][j-]-ans[i+][j-];
}
}
int m;
scanf ("%d",&m);
while (m--)
{
int L,R;
scanf ("%d%d",&L,&R);
printf ("%d\n",ans[L][R]);
}
return ;
}
int main ()
{
powseed[] = ;
for (int i = ; i <= maxn-; ++i) powseed[i] = powseed[i-] * seed;
int t;
scanf ("%d",&t);
while (t--) work();
return ;
}

HDU 4622 Reincarnation 后缀自动机 // BKDRHash(最优hash)的更多相关文章

  1. HDU 4622 Reincarnation 后缀自动机

    模板来源:http://blog.csdn.net/zkfzkfzkfzkfzkfzkfzk/article/details/9669747 解法参考:http://blog.csdn.net/dyx ...

  2. Hdu 4622 Reincarnation(后缀自动机)

    /* 字符串长度较小, 可以离线或者直接与处理所有区间的答案 动态加入点的时候, 因为对于其他点的parent构造要么没有影响, 要么就是在两个节点之间塞入一个点, 对于minmax的贡献没有改变 所 ...

  3. Reincarnation HDU - 4622 (后缀自动机)

    Reincarnation \[ Time Limit: 3000 ms\quad Memory Limit: 65536 kB \] 题意 给出一个字符串 \(S\),然后给出 \(m\) 次查询, ...

  4. hdu 4622 Reincarnation(后缀数组)

    hdu 4622 Reincarnation 题意:还是比较容易理解,给出一个字符串,最长2000,q个询问,每次询问[l,r]区间内有多少个不同的字串. (为了与论文解释统一,这里解题思路里sa数组 ...

  5. HDU 4622 Reincarnation Hash解法详解

    今天想学字符串hash是怎么弄的.就看到了这题模板题 http://acm.hdu.edu.cn/showproblem.php?pid=4622 刚开始当然不懂啦,然后就上网搜解法.很多都是什么后缀 ...

  6. HDU 4622 Reincarnation(后缀自动机)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4622 [题目大意] 给出一个长度不超过2000的字符串,有不超过10000个询问,问[L,R]子串 ...

  7. HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)

    Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  8. hdu 4622 Reincarnation SAM模板题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给定一个长度不超过2000的字符串,之后有Q次区间查询(Q <= 10000),问区 ...

  9. HDU 6583 Typewriter(后缀自动机)

    Typewrite \[ Time Limit: 1500 ms\quad Memory Limit: 262144 kB \] 题意 给出一个字符串 \(s\),现在你需要构造出这个字符串,你每次可 ...

随机推荐

  1. 【CF1027A】Palindromic Twist(模拟)

    题意:输入T组字符串,每个字符串都必须改变一次,每个字母改变的规则是变成相邻的字母,字母a只能变b,z只能变y,判断改变后的字符依旧是否能够变成回文串 n<=1e2 思路: #include&l ...

  2. 用node写的一个后台框架

    server.js var http=require('http') var handleUrl=require('./handleUrl') var config = require('./conf ...

  3. 禁用VMware的vmem文件

    新建一个虚拟机,VMWare会默认为其创建一个虚拟内存文件*.VMEM, 这个文件会影响系统的磁盘性能,所以最好关闭它. 该当是找到*.vmx文件,在文件最后加入一行 mainMem.useNamed ...

  4. js-数字渐增到指定的数字,在指定的时间内完成(有动画效果哦)插件jquery.animateNumber.js

    本来在项目中我自己实现的效果是数字由0渐增到指定的数字就好. 但是,最终效果不理想! Why? 最终指定的数字太大了,TMMD,滚动好久就不到,那用户想看自己有多少钱了,那不是就一直等着!!!所以这个 ...

  5. 使用vue-cli搭建element-ui项目

    最近在使用element-ui搭建项目时发现若只纯用webpack来运行element-ui,要配置各种文件,对于新手来说实在太不友好了, 就想到用vue-cli来搭建整个vue项目 1.安装node ...

  6. OceanBase数据库实践入门——手动搭建OceanBase集群

    前言 目前有关OceanBase功能.案例.故事的文章已经很多,对OceanBase感兴趣的朋友都想安装一个数据库试试.本文就是分享初学者如何手动搭建一个OceanBase集群.这也是学习理解Ocea ...

  7. Linux Root下的.gvfs出现异常解决办法(导致source失败,自启动失败)

    原文地址:   http://www.cnblogs.com/tdyizhen1314/p/4142991.html 在linux系统下安装软件或复制文件的时候,复制不成功,出现错误如下: error ...

  8. 被动路由跟踪工具InTrace

    被动路由跟踪工具InTrace   InTrace是一款类似于Traceroute的路由跟踪工具.但它不同的是,他不主动发送数据包,而是通过监听当前主机和目标主机的数据包,进行分析,从而获取路由信息. ...

  9. CF623

    AIM Tech Round (Div. 1) <br > 这真是一套极好的题目啊.....虽然我不会做 <br > 代码戳这里 <br > A.Graph and ...

  10. 记Weblogic采用RAC方式链接数据库遇到的问题

      前几天,去客户现场部署系统,WEBLOGIC连接数据库使用RAC方式连接,好几个人弄了一下午愣是没搞定,总是报SID错误 开始一致认为是防火墙的原因,后来SSH登陆应用服务器后,再TELNET数据 ...