LOJ#2083. 「NOI2016」优秀的拆分

$n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种。$t \leq 10$组询问。

$n^3$过80,$n^2$过95,鬼去写正解。。

$n^2$:先枚举一次算每个位置结尾的AA形式的子串,再枚举一次用类似的方法算答案。

正解:类似,记每个位置结尾的AA的子串和每个位置开头的即可。算这个数组可用如此方法:枚举A长度$L$,每A个位置标记一个关键点。然后相邻两个关键点$a,b$,找前缀$a,b$的最长公共后缀$p$和后缀$a,b$的最长公共前缀$s$,若$p+s>L$说明这里有一些A,其中作为起点的范围是$[a-p+1,a+s-L]$,作为终点的范围$[b-p+L,b+s-1]$,相当于做了个区间加,可以差分。这样做的话,复杂度就变成$\frac{n}{1}+\frac{n}{2}+...=n \ln n$了。

找最长公共前后缀,sa或二分hash或sam均可。

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 //#include<math.h>
  5 //#include<set>
  6 //#include<queue>
  7 //#include<bitset>
  8 //#include<vector>
  9 #include<algorithm>
 10 #include<stdlib.h>
 11 using namespace std;
 12 
 13 #define LL long long
 14 int qread()
 15 {
 16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
 17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
 18 }
 19 
 20 //Pay attention to '-' , LL and double of qread!!!!
 21 
 22 int T,n;
 23 #define maxn 60011
 24 char s[maxn]; int f[maxn],g[maxn];
 25 
 26 struct SAM
 27 {
 28     struct Node{int pre,ch[26],pos,Max;}a[maxn];
 29     int size,last;
 30     void clear()
 31     {
 32         size=last=0; a[0].pre=-1; a[0].pos=a[0].Max=0; memset(a[0].ch,0,sizeof(a[0].ch));
 33         le=2; memset(first,0,sizeof(first));
 34     }
 35     int pp[maxn];
 36     void insert(int c,int p)
 37     {
 38         int x=++size,y=last; memset(a[x].ch,0,sizeof(a[x].ch));
 39         a[x].Max=a[last].Max+1; a[x].pos=p; pp[p]=x;
 40         last=x;
 41         for (;~y && !a[y].ch[c];y=a[y].pre) a[y].ch[c]=x;
 42         if (!~y) a[x].pre=0;
 43         else if (a[a[y].ch[c]].Max==a[y].Max+1) a[x].pre=a[y].ch[c];
 44         else
 45         {
 46             int z=a[y].ch[c],w=++size; a[w]=a[z]; a[w].pos=p; a[w].Max=a[y].Max+1;
 47             a[z].pre=a[x].pre=w;
 48             for (;~y && a[y].ch[c]==z;y=a[y].pre) a[y].ch[c]=w;
 49         }
 50     }
 51     struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le;
 52     void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
 53     int Log[maxn<<1],rmq[22][maxn<<1],dep[maxn],Time,id[maxn];
 54     void predfs(int x)
 55     {
 56         rmq[0][++Time]=x; id[x]=Time;
 57         for (int i=first[x];i;i=edge[i].next)
 58         {
 59             Edge &e=edge[i]; dep[e.to]=dep[x]+1;
 60             predfs(e.to); rmq[0][++Time]=x;
 61         }
 62     }
 63     void pre()
 64     {
 65         for (int i=1;i<=size;i++) in(a[i].pre,i);
 66         Time=0; predfs(0);
 67         Log[0]=-1; for (int i=1,to=size*2-1;i<=to;i++) Log[i]=Log[i>>1]+1;
 68         for (int j=1;j<=18;j++)
 69             for (int i=1,to=size*2-(1<<j);i<=to;i++)
 70                 rmq[j][i]=dep[rmq[j-1][i]]>dep[rmq[j-1][i+(1<<(j-1))]]?rmq[j-1][i+(1<<(j-1))]:rmq[j-1][i];
 71     }
 72     int qq(int x,int y)
 73     {
 74         x=id[pp[x]]; y=id[pp[y]]; if (x>y) x^=y^=x^=y; int l=Log[y-x+1];
 75         return a[dep[rmq[l][x]]>dep[rmq[l][y-(1<<l)+1]]?rmq[l][y-(1<<l)+1]:rmq[l][x]].Max;
 76     }
 77 }s1,s2;
 78 //1 shi zheng de , 2 shi fan de
 79 
 80 int main()
 81 {
 82     T=qread();
 83     while (T--)
 84     {
 85         scanf("%s",s+1); n=strlen(s+1);
 86         s1.clear(); s2.clear();
 87         for (int i=1;i<=n;i++) s1.insert(s[i]-'a',i);
 88         for (int i=n;i;i--) s2.insert(s[i]-'a',i);
 89         s1.pre(); s2.pre();
 90         
 91         memset(f,0,sizeof(f));
 92         memset(g,0,sizeof(g));
 93         for (int i=1;i<=n;i++)
 94             for (int j=i;j<=n-i;j+=i)
 95             {
 96                 int k=j+i,p=s1.qq(j,k),s=s2.qq(j,k); p=min(p,i); s=min(s,i);
 97                 if (p+s>i) f[j-p+1]++,f[j+s-i+1]--,g[k-p+i]++,g[k+s]--;
 98             }
 99         
100         for (int i=1,now=0;i<=n;i++) now+=f[i],f[i]=now;
101         for (int i=1,now=0;i<=n;i++) now+=g[i],g[i]=now;
102         LL ans=0;
103         for (int i=1;i<n;i++) ans+=g[i]*1ll*f[i+1];
104         printf("%lld\n",ans);
105     }
106     return 0;
107 }
View Code

 

posted @ 2018-06-28 21:57  Blue233333  阅读(428)  评论(0编辑  收藏  举报