[后缀自动机 模板题 || 字符串Hash] HDU 4622 Reincarnation
2017-01-29 22:16
495 查看
题目大意:询问子串lr的不同子串数目
暴力建n次后缀自动机 存一下不同子串数目就好啦
不同子串数目
有两种做法 一种是按拓扑序DP
还有就是∑maxs(x)−maxs(fa(x))
显然第二种方法更好些 更通用
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一下就好了
暴力建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; }
相关文章推荐
- HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)
- HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)
- HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)
- hdu 4622 求区间不同子串数 后缀数组|后缀自动机|字符串hash
- 字符串(后缀自动机):HDU 4622 Reincarnation
- HDU 4622 Reincarnation 后缀自动机 // BKDRHash(最优hash)
- HDU 4622 Reincarnation 后缀自动机
- hdu 4622 Reincarnation (后缀自动机)
- hdu 4622 Reincarnation(后缀自动机,入门级)
- HDU - 4622 Reincarnation 后缀自动机
- HDU 4622 Reincarnation(后缀自动机)
- hdu 4622 Reincarnation (后缀自动机)
- HDU-4622 Reincarnation 后缀数组 | Hash,维护和,扫描
- hdu 4622 Reincarnation (后缀自动机)
- HDU 4622 Reincarnation(SAM 后缀自动机 求子串的不同子串个数)
- HDU 4622 Reincarnation(后缀自动机)
- HDU 4622 Reincarnation 后缀自动机
- HDU 4622 Reincarnation 后缀数组 或 后缀自动机
- Hdu 4622 Reincarnation 后缀数组/后缀自动机
- hdu 4622 Reincarnation(后缀自动机)