• 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
    ",ans);
    55     }
    56 }
    57 int sb=haha();
    58 int main(){;}
    uoj219

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

  • 相关阅读:
    ubuntu 18.04 搭建flask服务器(大合集,个人实操)
    Ubuntu18.04下Git安装及使用
    c#随机打乱数组
    c#递归获取目录下所有文件名称
    授人以渔:Keil配色界面较为详细的解释
    k8s存储资源之持久化存储资源存储卷PV与PVC理解与应用(七)
    Servlet总结
    Linux 系统目录结构
    make 编译笔记
    【Linux】Linux网络编程
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7588807.html
Copyright © 2020-2023  润新知