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$写法……以后再回来填吧……(有生之年系列

转载于:https://www.cnblogs.com/Loser-of-Life/p/7588807.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值