洛谷P5112 FZOUTSY(字符串哈希+莫队)
模板:后缀数组毒瘤
看见题面上的“后缀”、“$lcp$”等字样,dalao们大概马上想到后缀数组了。但是这道题能不能不用后缀数组呢?(其实是我不会后缀数组)
不难想到,$lcp\ge k$意味着两个字符串的前$k$个字符是相同的,于是大力字符串哈希,用$$(a_{1}x^{k-1}+a_{2}x^{k-2}+...+a_{k})*k-a_{1}x^{k}+a_{k+1}=a_{2}x^{k-1}+a_{3}x^{k-2}+...+a_{k+1}$$不难$O(n)$算出各个长度为$k$的子串的哈希值,接下来就是统计方案了。可以参考小Z的袜子,用莫队解决问题。
但是,$O(n\sqrt{n})$的莫队会被卡,所以要用块大小为$\frac{n}{\sqrt{m}}$的莫队,复杂度为$O(n\sqrt{m})$,对于$n^{2}m\le 10^{15}$,即$n\sqrt{m}\le 3.2*10^{7}$的数据,可以通过。
另外,模数太小的字符串哈希也会被卡,最好直接用unsigned long long,相当于模$2^{64}$,再对$n$个值离散化。
#include<cstdio> #include<cctype> #include<cmath> #include<algorithm> #define PC(A) putchar(A) using namespace std; typedef unsigned long long ll; const int N=3000050; const int M=100050; const int P=3000017; const int x=233; //233 char BB[1<<21],*S,*T; inline char gc(){return S==T&&(T=(S=BB)+fread(BB,1,1<<20,stdin),S==T)?EOF:*S++;} inline short rdc(){ char c=gc(); while(!islower(c))c=gc(); return c-'a'; } inline int rdi(){ char c=gc(); while(!isdigit(c))c=gc(); int x=c&15; for(c=gc();isdigit(c);c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } short buf[25]; inline void wt(ll x){ short l=-1; while(x>9){ buf[++l]=x%10; x/=10; } PC(x|48); while(l>=0)PC(buf[l--]|48); PC('\n'); } short a[N]; int h[P],nxt[N],p[N],cnt[N],l[M],r[M],t[M],n,k,sz,o=1; ll v[N],s[M]; inline void add(ll w){ int t=w%P; v[o]=w; nxt[o]=h[t]; h[t]=o; } inline int find(ll w){ int t=w%P,i; for(i=h[t];i;i=nxt[i])if(v[i]==w)return i; return 0; } //用哈希表实现离散化 inline ll fp(int p){ //快速幂 ll a=x,s=1; while(p){ if(p&1)s=s*a; a=a*a; p>>=1; } return s; } inline void work(){ int i,t; ll tmp=fp(k),res=0; for(i=1;i<=k;i++)res=res*x+a[i]; add(res); p[1]=1; for(i=k+1;i<=n;i++){ res=res*x-a[i-k]*tmp+a[i]; //前文的式子 if(t=find(res))p[i-k+1]=t; else{ p[i-k+1]=++o; add(res); } } } int cmp(int a,int b){return (l[a]-1)/sz==(l[b]-1)/sz?r[a]<r[b]:l[a]<l[b];} int main(){ int m,i,x,y; ll ans=0; n=rdi();m=rdi();k=rdi(); sz=n/sqrt(m); for(i=1;i<=n;i++)a[i]=rdc(); work(); for(i=0;i<m;i++){ l[i]=rdi();r[i]=rdi(); if(r[i]+k-1>n)r[i]=n-k+1; if(l[i]>r[i])l[i]=r[i]; //坑,小心这两种问题 t[i]=i; } sort(t,t+m,cmp); x=l[t[0]];y=r[t[0]]; for(i=x;i<=y;i++){ ans+=cnt[p[i]]; cnt[p[i]]++; } s[t[0]]=ans; for(i=1;i<m;i++){ if(l[t[i]]<x)do{ x--; ans+=cnt[p[x]]; cnt[p[x]]++; }while(x>l[t[i]]); else for(;x<l[t[i]];x++){ cnt[p[x]]--; ans-=cnt[p[x]]; } if(r[t[i]]>y)do{ y++; ans+=cnt[p[y]]; cnt[p[y]]++; }while(y<r[t[i]]); else for(;y>r[t[i]];y--){ cnt[p[y]]--; ans-=cnt[p[y]]; } s[t[i]]=ans; } //莫队 for(i=0;i<m;i++)wt(s[i]); return 0; }

浙公网安备 33010602011771号