uoj219 优秀的拆分 字符串

链接:http://uoj.ac/problem/219

题意:找出字符串之中所有符合$AABB$形式子串的划分方式。

这道题正解是$SA$……我不会……

然而二分+$Hash$可过……可过……

首先我们枚举每一个$A$的长度,然后我们二分长度搞出来各个位置与上一段的$LCS$,$LCP$长度。随后我们将$LCS$起点向左,$LCP$终点向右移动长度个字符,如果二者仍然没有相遇,差分相加。最后相邻的统计个数即可。

(语言说不太明白,还是上代码吧)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=50005,base=31;
 7 const int mod=998244353;
 8 char s[maxn];
 9 long long hash[maxn],t[maxn],u[maxn],v[maxn],ans;
10 inline long long gethash(int l,int r)
11 {
12     return ((hash[l]-hash[r]*t[r-l])%mod+mod)%mod;
13 }
14 int haha()
15 {
16     int T;scanf("%d",&T);
17     t[0]=1;for(int i=1;i<=30000;i++)t[i]=t[i-1]*base%mod;
18     while(T--)
19     {
20         scanf("%s",s+1);int n=strlen(s+1);
21         memset(u,0,sizeof(u)),memset(v,0,sizeof(v));
22         hash[n+1]=0;
23         for(int i=n;i;i--)hash[i]=(hash[i+1]*base+s[i]-'0'+1)%mod;
24         for(int len=1;(len<<1)<=n;len++)
25             for(int i=(len<<1);i<=n;i+=len)
26             {
27                 if(s[i]!=s[i-len])continue;
28                 int l=1,r=len,last=i-len,pos=0;
29                 while(l<=r)
30                 {
31                     int mid=(l+r)>>1;
32                     if(gethash(last-mid+1,last+1)==gethash(i-mid+1,i+1))l=mid+1,pos=mid;
33                     else r=mid-1;
34                 }
35                 int head=i-pos+1;
36                 l=1,r=len,pos=0;
37                 while(l<=r)
38                 {
39                     int mid=(l+r)>>1;
40                     if(gethash(last,last+mid)==gethash(i,i+mid))l=mid+1,pos=mid;
41                     else r=mid-1;
42                 }
43                 int tail=i+pos-1;
44                 head=max(head+len-1,i),tail=min(tail,i+len-1);
45                 if(head<=tail)
46                 {
47                     u[head-(len<<1)+1]++,u[tail+1-(len<<1)+1]--;
48                     v[head]++,v[tail+1]--;
49                 }
50             }
51         ans=0;
52         for(int i=1;i<=n;i++)u[i]+=u[i-1],v[i]+=v[i-1];
53         for(int i=1;i<n;i++)ans+=v[i]*u[i+1];
54         printf("%lld\n",ans);
55     }
56 }
57 int sb=haha();
58 int main(){;}
uoj219

至于$SA$写法……以后再回来填吧……(有生之年系列

posted @ 2017-09-24 21:40  ccc000111  阅读(296)  评论(1编辑  收藏  举报