• BZOJ4698 [SDOI2008] Sandy的卡片


    题意:求在N个串中都出现的最长子串 的长度

    很容易想到二分转化为判定性问题。考虑长度M,我们按照长度M进行分组,每个组内进行答案验证,即检查组内是否有N个串的后缀都出现。

    时间复杂度O(LlogM)

    其实是个经典题。

    二分时候记得初始化!

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 struct SA {
     5     int str[2100005];
     6     int x[2100005],y[2100005],u[2100005],v[2100005],r[2100005],o[2100005],hei[2100005],m=2100000,n,a[2100005];
     7     void build(int p,int l,int r){
     8         if(l==r) a[p]=hei[l];
     9         else build(p*2,l,(l+r)/2),build(p*2+1,(l+r)/2+1,r),a[p]=min(a[p*2],a[p*2+1]);
    10     }
    11     int query(int p,int l,int r,int ql,int qr){
    12         if(l>qr||r<ql) return 1e+9;
    13         if(l>=ql&&r<=qr) return a[p];
    14         return min(query(p*2,l,(l+r)/2,ql,qr),query(p*2+1,(l+r)/2+1,r,ql,qr));
    15     }
    16     void calc(){
    17         int i,j,k=0;
    18         for(i=1;i<=n;hei[r[i++]]=k)
    19             for(k?k--:0,j=x[r[i]-1];str[i+k]==str[j+k];k++);
    20     }
    21     int solve(){
    22         memset(r,0,sizeof r);
    23         for(int i=1;i<=n;i++) u[str[i]]++;
    24         for(int i=1;i<=m;i++) u[i]+=u[i-1];
    25         for(int i=n;i>=1;i--) x[u[str[i]]--]=i;
    26         r[x[1]]=1;
    27         for(int i=2;i<=n;i++) r[x[i]]=r[x[i-1]]+((str[x[i]]-str[x[i-1]])?1:0);
    28         for(int l=1;r[x[n]]<n;l<<=1) {
    29             memset(u,0,sizeof u); memset(v,0,sizeof v); memcpy(o,r,sizeof r);
    30             for(int i=1;i<=n;i++) u[r[i]]++, v[(i+l<=n)?r[i+l]:0]++;
    31             for(int i=1;i<=n;i++) u[i]+=u[i-1], v[i]+=v[i-1];
    32             for(int i=n;i>=1;i--) y[v[(i+l<=n)?r[i+l]:0]--]=i;
    33             for(int i=n;i>=1;i--) x[u[r[y[i]]]--]=y[i];
    34             r[x[1]]=1;
    35             for(int i=2;i<=n;i++) r[x[i]]=r[x[i-1]]+
    36                 ((o[x[i]]!=o[x[i-1]])||(((x[i]+l<=n)?o[x[i]+l]:0)!=((x[i-1]+l<=n)?o[x[i-1]+l]:0)));
    37         }
    38         calc();
    39         hei[1]=0;
    40     }
    41     int lcp(int pos1,int pos2) {return query(1,1,n,min(r[pos1],r[pos2])+1,max(r[pos1],r[pos2]));}
    42 } sa;
    43 
    44 int n,k;
    45 int len[2100005],str[2100005],src[2100005],x[1005],delta;
    46 
    47 int main(){
    48     ios::sync_with_stdio(false);
    49     cin>>n;
    50     for(int i=1;i<=n;i++) {
    51         cin>>len[i];
    52         for(int j=1;j<=len[i];j++) {
    53             cin>>str[j];
    54         }
    55         for(int j=len[i];j>=2;j--){
    56             str[j]-=str[j-1];
    57         }
    58         for(int j=1;j<=len[i];j++){
    59             str[j]+=1000100;
    60         }
    61         sa.str[len[i-1]]=i;
    62         memcpy(sa.str+len[i-1]+1,str+1,len[i]*sizeof(int));
    63         len[i]+=len[i-1]+1;
    64         
    65     }
    66     sa.n=len[n]-1;
    67     sa.solve();
    68     for(int i=1;i<=n;i++)
    69         for(int j=len[i-1]+1;j<=len[i]-1;j++)
    70             src[j]=i;
    71     int left=1,right=len[n]-1,ans;
    72     while(left-right){
    73         memset(x,0,sizeof x);
    74         int mid=(left+right)/2;
    75         for(int i=1;i<=len[n]-1;i++) {
    76             if(sa.hei[i]<mid-1) {
    77                 int flag=1;
    78                 for(int j=1;j<=n;j++) 
    79                     if(x[j]==0) {
    80                         flag=0;
    81                         break;
    82                     }
    83                 if(flag) {
    84                     ans=mid;
    85                     break;
    86                 }
    87                 memset(x,0,sizeof x);
    88             }
    89             x[src[sa.x[i]]]++;
    90         }
    91         if(ans==mid) left=mid+1;
    92         else right=mid;
    93     }
    94     printf("%d
    ",ans);
    95 }
  • 相关阅读:
    php数组
    php数组排序
    php超级全局变量
    php循环
    php函数
    PHP魔术常量
    php面向对象
    static 关键字
    Final 关键字
    内置函数
  • 原文地址:https://www.cnblogs.com/mollnn/p/8443396.html
Copyright © 2020-2023  润新知