• 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 
    ",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
    ",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
    ",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
    ",i+l-lcs,i+lcp-1);
     98                     beg[i-l-lcs+1]++,beg[i-2*l+lcp+1]--;
     99                     // printf("add B:%d %d
    ",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
    ",ans);
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    DataTablez转List对象效率慢的问题.
    Oracle 删除重复数据
    1.layui 添加旋转等待, 2.div里面加载HTML页面
    layui-table JSON.stringify()序列化出来的不同行数据类型错误.导致后台转成表格的时候出错.(常用)
    0基础学MVC课程
    构造函数的执行顺序
    html控件自动点 “加号”添加 多个附件
    C#委托之个人理解 转自 loose_went
    一步一步学Linq to sql系列文章 转lovecherry
    使用AOP 使C#代码更清晰 转yanghua_kobe
  • 原文地址:https://www.cnblogs.com/Ressed/p/10200830.html
Copyright © 2020-2023  润新知