zoukankan      html  css  js  c++  java
  • [BZOJ]4650 优秀的拆分(Noi2016)(哈希+二分)

    传送门

     
    题解
      听说大佬们这题都是用SA秒掉的
      然而SA的时间复杂度的确很优秀,缺点就是看不太懂……
      然后发现一位大佬用哈希华丽的过了此题,而且讲的特别清楚->这里
      我们只要考虑以每一个点结尾的$AA$串的个数$u[i]$和以每一个点开头的AA串的个数$v[i]$,答案就是$sum _{i=1}^{n-1} u[i]*v[i+1]$
      那么考虑如何求出$u$和$v$呢
      我们考虑一下,枚举串$A$的长度$len$,然后每隔$len$个单位设置一个关键点。不难发现,每一个长度为$len*2$的$AA$串,必定经过两个关键点
      然后考虑,只要求出相邻两个关键点往前的$LCS$和往后的$LCP$,如果$LCS+LCP>=len$,就表明存在长度为$len$的$AA$串。而且不难发现,所有经过这两个关键点的长度为$len$的$AA$串,肯定是连续的!所以我们可以找到这个区间,然后用前缀和差分,就可以避免区间修改了
      说了这么多,到底怎么求$LCS$和$LCP$呢?(大佬:SA+ST表不是随便过的么)嗯,没错,二分。我们二分它们的长度,然后用哈希判断是否相等。这样虽然时间复杂度比起ST表多了个$log$,但起码更看得懂……
      时间复杂度是枚举$len$的调和级数,加上二分,为$O(nlog^2n)$
      ps:话说我也不明白调和级数是个什么玩意儿,只要知道枚举的复杂度是$sum _{i=1}^n frac{n}{i} =O(nlogn)$就行了……
      pps:管那么多干嘛能A不就行了么……话说这题明明纯哈希暴力就有95……某大佬讲课的时候还以这题为例嘲笑NOI近几年的出题水平(逃)
     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #define ll long long
     7 using namespace std;
     8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     9 char buf[1<<21],*p1=buf,*p2=buf;
    10 inline int read(){
    11     #define num ch-'0'
    12     char ch;bool flag=0;int res;
    13     while(!isdigit(ch=getc()))
    14     (ch=='-')&&(flag=true);
    15     for(res=num;isdigit(ch=getc());res=res*10+num);
    16     (flag)&&(res=-res);
    17     #undef num
    18     return res;
    19 }
    20 char sr[1<<21],z[20];int C=-1,Z;
    21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    22 inline void print(ll x){
    23     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    24     while(z[++Z]=x%10+48,x/=10);
    25     while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    26 }
    27 const int N=30005,mod=3e7+7;
    28 char s[N];int n;
    29 ll hash[N],mo[N],u[N],v[N],ans;
    30 inline ll gethash(int l,int r){
    31     ll now=hash[l]-hash[r]*mo[r-l];
    32     now%=mod,now+=mod,now%=mod;
    33     return now;
    34 }
    35 int main(){
    36     int T=read();mo[0]=1;for(int i=1;i<=30000;++i) mo[i]=mo[i-1]*31%mod;
    37     while(T--){
    38         n=0;char ch;
    39         while((ch=getc())!='
    ') s[++n]=ch;
    40         memset(u,0,sizeof(u)),memset(v,0,sizeof(v));
    41         hash[n+1]=0;
    42         for(int i=n;i;--i) (hash[i]=hash[i+1]*31+s[i]-'a'+1)%=mod;
    43         for(int L=1;L*2<=n;++L){
    44             for(int i=L<<1;i<=n;i+=L){
    45                 if(s[i]!=s[i-L]) continue;
    46                 int l=1,r=L,last=i-L,pos=0;
    47                 //二分查找lcp和lcs 
    48                 while(l<=r){
    49                     int mid=l+r>>1;
    50                     if(gethash(last-mid+1,last+1)==gethash(i-mid+1,i+1)) pos=mid,l=mid+1;
    51                     else r=mid-1;
    52                 }
    53                 int head=i-pos+1;
    54                 l=1,r=L,pos=0;
    55                 while(l<=r){
    56                     int mid=l+r>>1;
    57                     if(gethash(last,last+mid)==gethash(i,i+mid)) pos=mid,l=mid+1;
    58                     else r=mid-1;
    59                 }
    60                 int tail=i+pos-1;
    61                 head=max(head+L-1,i);//防止越过两块 
    62                 tail=min(tail,i+L-1);//防止跑到后面的块 
    63                 if(head<=tail){
    64                     ++u[head-2*L+1],--u[tail+1-2*L+1];
    65                     ++v[head],--v[tail+1];
    66                     //为了差分
    67                     //因为head-2*L+1到tail-2*L+1开头的AA串增加的
    68                     //以他们的答案都可以++
    69                     //然后以head到tail结尾的AA串也++ 
    70                 }
    71             }
    72         }
    73         ans=0;
    74         for(int i=1;i<=n;++i) u[i]+=u[i-1],v[i]+=v[i-1];
    75         for(int i=1;i<n;++i) ans+=v[i]*u[i+1];
    76         print(ans);
    77     }
    78     Ot();
    79     return 0;
    80 }
     
     
  • 相关阅读:
    不为人知easy-mock-cli
    javascript设计模式之适配器模式
    js --装饰者模式
    使用策略模式封装拦截器
    js --桥接模式
    深入理解面向对象 -- 基于 JavaScript 实现
    设计模式 -- 观察者模式
    敏捷开发
    从技术走向管理
    Vue Cli安装以及使用
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9470029.html
Copyright © 2011-2022 走看看