zoukankan      html  css  js  c++  java
  • 【HDOJ5558】Alice's Classified Message(后缀数组)

    题意:给定一个长度为n的下标从0开始的小写字母字符串,每次对于当前的i寻找一个j使得后缀i与后缀j的lcp最大,(j<i)若lcp相同则取较小的

    若lcp为0则输出0与当前字符,i自增1,否则输出lcp的值与j,i自增lcp的值,以上过程重复直到i>=n

    要求模拟这个过程

    n<=1e5,sigma n<=2e6

    思路:显然后缀的lcp要用到后缀数组

    考虑对于每一个i都直接枚举j不可做,对于rank而言可以预处理出每一段连续的height大于0的起始位置和结束位置,在段中往左右两侧暴力枚举

    满足要求的条件为:sa[j]<i,且连续的height的min的值不减

    这个暴力扫描的复杂度应该假了(真的吗),但数据卡不掉……

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 typedef long long ll;
      6 using namespace std;
      7 #define N   110000 
      8 #define oo  10000000
      9 #define MOD 100000073
     10 
     11 
     12 char ch[N];
     13 int n,i,s[N],sa[N],wa[N],wb[N],wc[N],wd[N],height[N],Rank[N],pre[N],nxt[N];
     14 
     15 bool cmp(int *r,int a,int b,int l)
     16 {
     17     return r[a]==r[b]&&r[a+l]==r[b+l];
     18 }
     19 
     20 void getsa(int *r,int *sa,int n,int m)
     21 {
     22     int *x=wa,*y=wb,j,p;
     23     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
     24     for(i=1;i<m;i++) wc[i]+=wc[i-1];
     25     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
     26     for(j=1,p=1;p<n;j*=2,m=p)
     27     {
     28         p=0;
     29         for(i=n-j;i<n;i++) y[p++]=i;
     30         for(i=0;i<n;i++)
     31          if(sa[i]>=j) y[p++]=sa[i]-j;
     32         for(i=0;i<n;i++) wd[i]=x[y[i]];  
     33         for(i=0;i<m;i++) wc[i]=0;
     34         for(i=0;i<n;i++) wc[wd[i]]++;
     35         for(i=1;i<m;i++) wc[i]+=wc[i-1];
     36         for(i=n-1;i>=0;i--) sa[--wc[wd[i]]]=y[i];
     37         swap(x,y);
     38         p=1; x[sa[0]]=0;
     39         for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     40         if(j>n) break; 
     41     } 
     42 }
     43 
     44 void getheight(int *r,int *sa,int n)
     45 {
     46     int i,j,k=0;
     47     for(i=1;i<=n;i++) Rank[sa[i]]=i;
     48     for(i=0;i<n;height[Rank[i++]]=k)
     49     {
     50         if(k) k--;
     51         j=sa[Rank[i]-1];
     52         while(r[i+k]==r[j+k]) k++;
     53     }
     54 }
     55 
     56 void init()
     57 {    
     58         memset(s,0,sizeof(s));
     59         memset(sa,0,sizeof(sa));
     60         memset(wa,0,sizeof(wa));
     61         memset(wb,0,sizeof(wb));
     62         memset(wc,0,sizeof(wc));
     63         memset(wd,0,sizeof(wd));
     64         memset(height,0,sizeof(height));
     65         memset(Rank,0,sizeof(Rank));
     66 }
     67 
     68 int main()
     69 { 
     70     int cas; 
     71     scanf("%d",&cas);
     72     for(int v=1;v<=cas;v++)
     73     {
     74         init();
     75         printf("Case #%d:
    ",v);
     76         scanf("%s",ch);
     77         n=strlen(ch);
     78         for(int i=0;i<n;i++) s[i]=ch[i]-'a'+1;
     79         s[n]=0;
     80         getsa(s,sa,n+1,100);
     81         getheight(s,sa,n);
     82         for(int i=1;i<=n;i++)
     83          if(!height[i]) pre[i]=i;
     84           else pre[i]=pre[i-1];
     85         for(int i=n;i>=1;i--)
     86          if(height[i+1]==0||i==n) nxt[i]=i;
     87           else nxt[i]=nxt[i+1];
     88         int i=0;
     89         while(i<n)
     90         {
     91             int now=Rank[i];
     92             int k=0; 
     93             int t=i;
     94             int mn=height[now];
     95             for(int j=now-1;j>=pre[now];j--)
     96             {
     97                 mn=min(mn,height[j+1]);
     98                 if(mn<k) break;
     99                 if(sa[j]<i)
    100                 {
    101                     if(mn>k||mn==k&&sa[j]<t)
    102                     {
    103                         k=mn; t=sa[j];
    104                     }
    105                 }
    106             }
    107             if(now+1<=nxt[now]) mn=height[now+1];
    108             for(int j=now+1;j<=nxt[now];j++)
    109             {
    110                 mn=min(mn,height[j]);
    111                 if(mn<k) break;
    112                 if(sa[j]<i)
    113                 {
    114                     if(mn>k||mn==k&&sa[j]<t)
    115                     {
    116                         k=mn; t=sa[j];
    117                     }
    118                 }
    119             }
    120             if(!k)
    121             {
    122                 printf("-1 %d
    ",ch[i]);
    123                 i++;
    124             }
    125              else
    126              {
    127                  printf("%d %d
    ",k,t);
    128                  i+=k;
    129              }
    130         }        
    131     }
    132     return 0;
    133 }
    134     
  • 相关阅读:
    ASP.NET2.0服务器控件之自定义状态管理
    sql中RIGHT和LEFT(小技巧)
    微软云计算的思考
    枚举转化和判断方法的总结
    sql中的split(小技巧)
    ASP.net实现无扩展名的URL重写。简单、方便、无需ISAPI
    浅析值类型与引用类型的内存分配
    ASP.Net Web Page深入探讨
    const和static readonly 区别
    程序中一种用in的sql防注入的方法(小技巧)
  • 原文地址:https://www.cnblogs.com/myx12345/p/10003366.html
Copyright © 2011-2022 走看看