您的位置:首页 > 其它

[后缀自动机 模板题 || 字符串Hash] HDU 4622 Reincarnation

2017-01-29 22:16 495 查看
题目大意:询问子串lr的不同子串数目

暴力建n次后缀自动机 存一下不同子串数目就好啦

不同子串数目

有两种做法 一种是按拓扑序DP

还有就是∑maxs(x)−maxs(fa(x))

显然第二种方法更好些 更通用

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int read(char *s){
char c=nc(); int len=0;
for (;!(c>='a' && c<='z');c=nc());
for (;c>='a' && c<='z';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}

const int N=4005;

struct state{
int link,len,next[26];
}st
;
int ncnt,last;

inline void Extend(char c){
int cur=++ncnt,p; c-='a';
st[cur].len=st[last].len+1;
for (p=last;p!=-1 && !st[p].next[c];p=st[p].link)
st[p].next[c]=cur;
if (p==-1)
st[cur].link=0;
else{
int q=st[p].next[c];
if (st[q].len==st[p].len+1)
st[cur].link=q;
else{
int nq=++ncnt;
st[nq].len=st[p].len+1;
st[nq].link=st[q].link;
for (int i=0;i<26;i++) st[nq].next[i]=st[q].next[i];
for (;p!=-1 && st[p].next[c]==q;p=st[p].link)
st[p].next[c]=nq;
st[q].link=st[cur].link=nq;
}
}
last=cur;
}

char S[N>>1]; int n;
int ans[N>>1][N>>1];

int main(){
int T,Q,l,r;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T);
while (T--){
n=read(S);
for (int i=1;i<=n;i++){
st[0].link=-1;
for (int j=i;j<=n;j++){
Extend(S[j]);
ans[i][j]=ans[i][j-1]+st[last].len-st[st[last].link].len;
}
memset(st,0,sizeof(state)*(ncnt+5)); ncnt=last=0;
}
read(Q);
while (Q--){
read(l); read(r);
printf("%d\n",ans[l][r]);
}
}
return 0;
}


UPD 2017/1/30

get到一个很好地hash做法 hdu 4622 Reincarnation 字符串hash 模板题

枚举长度做hash

我们对f[i][i+L−1]打+1标记

这样会重复 怎么去重

令p为这个串上一次出现的位置 f[p][i+L−1]打-1标记

最后答案 ans(l,r)=∑l<=i<=r∑l<=j<=rf[i][j]

DP一下就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef unsigned long long ull;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int read(char *s){
char c=nc(); int len=0;
for (;!(c>='a' && c<='z');c=nc());
for (;c>='a' && c<='z';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}

const int P=100007;
const int N=2005;

namespace Hash{
int head[P],inum;
int next
,pos
; ull val
;
void clear(){
inum=0; cl(head);
}
int ins(ull v,int p){
int hash=v%P;
for(int i=head[hash];i;i=next[i])
if(v==val[i])
return swap(p,pos[i]),p;
pos[++inum]=p; val[inum]=v; next[inum]=head[hash]; head[hash]=inum;
return 0;
}
}

int n; char S
;
const int SEED=13331;
ull seed
,s
;
int f

;

int main(){
int T; using namespace Hash;
freopen("t.in","r",stdin);
freopen("t1.out","w",stdout);
seed[0]=1; for (int i=1;i<N;i++) seed[i]=seed[i-1]*SEED;
read(T);
while (T--){
n=read(S);
s[0]=0;
for (int i=1;i<=n;i++) s[i]=s[i-1]*SEED+S[i];
memset(f,0,sizeof(f));
for (int l=1;l<=n;l++){
clear();
for (int i=1,j;i+l-1<=n;i++)
j=ins(s[i+l-1]-s[i-1]*seed[l],i),f[i][i+l-1]++,f[j][i+l-1]--;
}
for (int i=1;i<=n;i++)
for (int l=1,r;l+i-1<=n;l++)
r=l+i-1,f[l][r]+=f[l+1][r]+f[l][r-1]-f[l+1][r-1];
int Q,l,r;
read(Q);
while (Q--){
read(l); read(r);
printf("%d\n",f[l][r]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: