luogu1117 优秀的拆分 (后缀数组)

考虑分别计算每个位置作为AA的末尾或者BB的开头的个数 最后乘一乘就是答案

据说是套路的计算AA的方法:

首先枚举A的长度L,然后每L个字符当做一个关键点,这样的话,一个AA包含且只包含相邻两个关键点(记为a,b),而且满足lcp(a,b)+lcs(a,b)-1>=L 手画一下就能看出来

于是SA搞lcp 倒过来再SA搞lcs 最后差分一下统计答案即可

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 #define MP make_pair
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=3e4+10;
  8 
  9 inline char gc(){
 10     return getchar();
 11     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
 12     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
 13 }
 14 inline ll rd(){
 15     ll x=0;char c=gc();bool neg=0;
 16     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
 17     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
 18     return neg?(~x+1):x;
 19 }
 20 
 21 char str[maxn];
 22 int lg2[maxn],N;
 23 
 24 struct SA{
 25     int cnt[maxn*2],tmp[maxn*2],rnk[maxn*2],sa[maxn*2],hei[maxn];
 26     int st[maxn][20],n;
 27     
 28     inline void build(char *s){
 29         int i,j=0,k,m=26;
 30         CLR(cnt,0);CLR(rnk,0);
 31         for(i=1;i<=n;i++) cnt[s[i]-'a']=1;
 32         for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
 33         for(i=1;i<=n;i++) rnk[i]=cnt[s[i]-'a'];
 34         for(k=1;j!=n;k<<=1){
 35             CLR(cnt,0);
 36             for(i=1;i<=n;i++) cnt[rnk[i+k]]++; 
 37             for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
 38             for(i=n;i;i--) tmp[cnt[rnk[i+k]]--]=i;
 39             CLR(cnt,0);
 40             for(i=1;i<=n;i++) cnt[rnk[i]]++;
 41             for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
 42             for(i=n;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i];
 43             memcpy(tmp,rnk,sizeof(rnk));
 44             rnk[sa[1]]=j=1;
 45             for(i=2;i<=n;i++){
 46                 if(tmp[sa[i]]!=tmp[sa[i-1]]||tmp[sa[i]+k]!=tmp[sa[i-1]+k]) j++;
 47                 rnk[sa[i]]=j;
 48             }m=j;
 49         }
 50         
 51         hei[1]=0;
 52         for(i=1,j=0;i<=n;i++){
 53             if(rnk[i]==1) continue;
 54             if(j) j--;
 55             int x=sa[rnk[i]-1];
 56             while(i+j<=n&&x+j<=n&&s[i+j]==s[x+j]) j++;
 57             hei[rnk[i]]=j;
 58         }
 59         // for(i=1;i<=n;i++) printf("hei:%d %d ; rnk:%d ; sa:%d \n",i,hei[i],rnk[i],sa[i]);
 60         for(i=n;i;i--){
 61             st[i][0]=hei[i];
 62             for(j=1;i+(1<<j)-1<=n;j++){
 63                 st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
 64             }
 65         }
 66     }
 67     
 68     inline int query(int x,int y){ //x,y:pos
 69         if(x==y) return n-y+1;
 70         int l=min(rnk[x],rnk[y])+1,r=max(rnk[x],rnk[y]);
 71         // printf("~%d %d\n",l,r);
 72         int k=lg2[r-l+1];
 73         return min(st[l][k],st[r-(1<<k)+1][k]);
 74     }
 75 }fw,bw;
 76 
 77 int end[maxn],beg[maxn];
 78 
 79 int main(){
 80     //freopen("","r",stdin);
 81     int i,j,k;
 82     for(i=2;i<=30000;i++) lg2[i]=lg2[i>>1]+1;
 83     for(int T=rd();T;T--){
 84         scanf("%s",str+1);N=strlen(str+1);
 85         fw.n=bw.n=N;
 86         fw.build(str);
 87         reverse(str+1,str+N+1);
 88         bw.build(str);
 89         CLR(end,0);CLR(beg,0);
 90         for(int l=1;l<=N;l++){
 91             i=l+1;
 92             for(;i<=N;i+=l){
 93                 int lcp=min(l,fw.query(i-l,i)),lcs=min(l,bw.query(N-i+1,N-(i-l)+1));
 94                 // printf("!%d %d %d %d\n",i,i-l,lcp,lcs);
 95                 if(lcp+lcs-1>=l){
 96                     end[i+l-lcs]++,end[i+lcp]--;
 97                     // printf("add A:%d %d\n",i+l-lcs,i+lcp-1);
 98                     beg[i-l-lcs+1]++,beg[i-2*l+lcp+1]--;
 99                     // printf("add B:%d %d\n",i-l-lcs+1,i-2*l+lcp);
100                 }
101             }
102         }
103         for(i=1;i<=N;i++) end[i]+=end[i-1],beg[i]+=beg[i-1];
104         ll ans=0;
105         for(i=1;i<N;i++){
106             ans+=end[i]*beg[i+1];
107         }
108         printf("%lld\n",ans);
109     }
110     return 0;
111 }

 

posted @ 2018-12-30 21:53  Ressed  阅读(226)  评论(0编辑  收藏  举报