[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 }
View Code

 

posted @ 2022-04-07 21:00  PYWBKTDA  阅读(61)  评论(0编辑  收藏  举报