[cf1043G]Speckled Band
结论:若答案不为$-1$,则答案$\le 4$
对$s[l,r]$中是否存在相同字符分类讨论:
1.若$s[l,r]$中字符各不相同,显然答案为$-1$,与假设矛盾
2.若$s[l,r]$中存在相同字符,在其中两个字符旁划分,显然合法且答案$\le 4$
考虑依次判定答案能否为1、2、3或4,具体如下——
1.答案为1当且仅当$s[l,r]$为循环串
枚举循环节长度$d\mid (r-l+1)$,并后缀数组+ST表$o(1)$求$lcp(suf_{l},suf_{l+d})$即可
2.答案为2当且仅当$s[l,r]$存在前缀/后缀为循环串或前缀等于后缀
(默认更小的答案条件均已判定且不满足,下同)
充分性:前者显然,后者在前缀和后缀有交时将交作为新的前(后)缀即可
必要性:反证法,假设条件均不满足时答案为2,记对应划分为$A_{1}A_{2}...A_{m}$
显然$m\ge 3$,进而根据假设可得$A_{1}\ne A_{2},A_{m-1}\ne A_{m}$且$A_{1}\ne A_{m}$
结合答案为2,可得$A_{2}=A_{m}$且$A_{m-1}=A_{1}$,进而$A_{1}A_{2}=A_{m-1}A_{m}$,与假设矛盾
前者可以参考[NOI2016]优秀的划分做到$o(n\log n)$(同样$o(1)$求$lcp/lcs$)
另外,预处理出的即以每一个位置为左/右端点的最短循环串,进而用并查集修改即可
后者可以参考[BJWC2018]Border的四种求法或基本字典子串做到$o(m\log^{2}n)$或$o(m\log n)$
另外,本题中仅需判定,有$o(m\sqrt{n})$的做法:
考虑找最短的前缀等于后缀,则该串不存在前缀等于后缀,进而出现位置不交
长度$\le \sqrt{n}$可以暴力检验,长度$>\sqrt{n}$则其至多出现$\sqrt{n}$次,进而在排名与$l$相差不超过$\sqrt{n}$
3.答案为3当且仅当$s[l,r]$存在循环子串或$s_{l/r}$在其他位置出现
充分性:两者均显然
必要性:反证法,假设条件均不满足时答案为3,记对应划分为$A_{1}A_{2}...A_{m}$
显然$m\ge 4$,进而根据假设可得$A_{1},A_{2},A_{3}$各不相同($A_{1}$若相同即$s_{l}$与其第一个字符相同)
结合答案为3,可得$A_{m}\in \{A_{1},A_{2},A_{3}\}$,进而$s_{r}$与对应字符串最后一个字符相同
前者即在之前的基础上区间取$\min$,后者可以$o(n|\alpha|)$预处理并简单判定
4.答案为4当且仅当$s[l,r]$中存在相同字符,显然可以做到$o(m|\alpha|)$
最终,总复杂度为$o(n\log n+n|\alpha|+m\sqrt{n}+m|\alpha|)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define D 26 5 #define L 18 6 int n,q,K,l,r,lg[N],mn[N],mx[N],Mn[N][L],cnt[D],Cnt[N][D]; 7 char s[N]; 8 struct SA{ 9 int m,a[N],b[N],c[N],tot[N],rk[N<<1],sa[N],h[N],H[N][L],ans[N]; 10 void build(){ 11 m=26; 12 for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1; 13 for(int i=1;;i<<=1){ 14 memset(tot,0,sizeof(tot)); 15 for(int j=1;j<=n;j++)tot[rk[j+i]]++; 16 for(int j=1;j<=m;j++)tot[j]+=tot[j-1]; 17 for(int j=n;j;j--)a[tot[rk[j+i]]--]=j; 18 memset(tot,0,sizeof(tot)); 19 for(int j=1;j<=n;j++)tot[rk[j]]++; 20 for(int j=1;j<=m;j++)tot[j]+=tot[j-1]; 21 for(int j=n;j;j--)b[tot[rk[a[j]]]--]=a[j]; 22 m=0; 23 for(int j=1;j<=n;j++){ 24 if ((j==1)||(rk[b[j]]!=rk[b[j-1]])||(rk[b[j]+i]!=rk[b[j-1]+i]))m++; 25 c[b[j]]=m; 26 } 27 memcpy(rk,c,sizeof(c)); 28 if (m==n)break; 29 } 30 for(int i=1;i<=n;i++)sa[rk[i]]=i; 31 for(int i=1,j=0;i<=n;i++){ 32 int ii=sa[rk[i]+1];j=max(j-1,0); 33 while ((max(i,ii)+j<=n)&&(s[i+j]==s[ii+j]))j++; 34 h[rk[i]]=j; 35 } 36 for(int i=n-1;i;i--){ 37 H[i][0]=h[i]; 38 for(int j=1;j<L;j++)H[i][j]=min(H[i][j-1],H[min(i+(1<<j-1),n-1)][j-1]); 39 } 40 } 41 int query(int x,int y){ 42 if (x==y)return n-x+1; 43 x=rk[x],y=rk[y]; 44 if ((!x)||(!y))return 0; 45 if (x>y)swap(x,y); 46 int m=lg[y-x]; 47 return min(H[x][m],H[y-(1<<m)][m]); 48 } 49 }T0,T1; 50 struct Union{ 51 int fa[N],ans[N]; 52 int find(int k){ 53 if (k==fa[k])return k; 54 return fa[k]=find(fa[k]); 55 } 56 void build(){ 57 for(int i=1;i<=n+1;i++)fa[i]=i; 58 } 59 void upd(int l,int r,int x){ 60 while (1){ 61 l=find(l); 62 if (l>r)break; 63 fa[l]=l+1,ans[l]=x; 64 } 65 } 66 }F0,F1; 67 int lcp(int x,int y){ 68 return T0.query(x,y); 69 } 70 int lcs(int x,int y){ 71 return T1.query(n-x+1,n-y+1); 72 } 73 int query(int l,int r){ 74 int m=lg[r-l+1]; 75 return min(Mn[l][m],Mn[r-(1<<m)+1][m]); 76 } 77 int calc(int l,int r){ 78 int len=r-l+1; 79 for(int i=1;i*i<=len;i++) 80 if (len%i==0){ 81 if ((i<len)&&(lcp(l,l+i)>=len-i))return 1; 82 if ((i>1)&&(i*i!=len)&&(lcp(l,l+len/i)>=len-len/i))return 1; 83 } 84 if ((mn[l]<=r)||(mx[r]>=l))return 2; 85 for(int i=max(r-K,l+1);i<=r;i++) 86 if (lcp(l,i)>=r-i+1)return 2; 87 for(int i=max(T0.rk[l]-K,1);i<=min(T0.rk[l]+K,n);i++){ 88 int j=T0.sa[i]; 89 if ((l<j)&&(j<=r)&&(lcp(l,j)>=r-j+1))return 2; 90 } 91 if (query(l,r)<=r)return 3; 92 for(int c=0;c<D;c++)cnt[c]=Cnt[r][c]-Cnt[l-1][c]; 93 if ((cnt[s[l]-'a']>1)||(cnt[s[r]-'a']>1))return 3; 94 for(int c=0;c<D;c++) 95 if (cnt[c]>1)return 4; 96 return -1; 97 } 98 int main(){ 99 scanf("%d%s%d",&n,s+1,&q); 100 K=(int)sqrt(n),lg[0]=-1; 101 for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1; 102 T0.build(),reverse(s+1,s+n+1),T1.build(),reverse(s+1,s+n+1); 103 F0.build(),F1.build(); 104 for(int i=1;i<=n;i++) 105 for(int j=i;j+i<=n;j+=i){ 106 int x=max(i-lcp(j+1,j+i+1),1),y=min(lcs(j,j+i),i); 107 if (x<=y)F0.upd(j-y+1,j-x+1,i),F1.upd(j+(i<<1)-y,j+(i<<1)-x,i); 108 } 109 for(int i=1;i<=n;i++){ 110 if (!F0.ans[i])mn[i]=n+1; 111 else mn[i]=i+(F0.ans[i]<<1)-1; 112 if (!F1.ans[i])mx[i]=0; 113 else mx[i]=i-(F1.ans[i]<<1)+1; 114 } 115 for(int i=n;i;i--){ 116 Mn[i][0]=mn[i]; 117 for(int j=1;j<L;j++)Mn[i][j]=min(Mn[i][j-1],Mn[min(i+(1<<j-1),n)][j-1]); 118 } 119 for(int i=1;i<=n;i++) 120 for(int c=0;c<D;c++)Cnt[i][c]=Cnt[i-1][c]+(s[i]-'a'==c); 121 for(int i=1;i<=q;i++){ 122 scanf("%d%d",&l,&r); 123 printf("%d\n",calc(l,r)); 124 } 125 return 0; 126 }