zoukankan      html  css  js  c++  java
  • SPOJ

    传送门:SPOJ - PHRASES(后缀数组+二分)

    题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次。

    题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡(哭... 

    首先是多个字符串的常规操作(目前写的题少,见到的都是这样)连成一个字符串,中间用不同的且没出现过的字符隔开。然后后缀数组求出sa数组和height数组,二分子串长度,用mx数组记录该串中的这个子串的起点最大值,mi数组记录最小值,如果所有串中的mx-mi都>=k说明这个长度可以。

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<queue>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<cstring>
      7 using namespace std;
      8 
      9 //sa:字典序中排第i位的起始位置在str中第sa[i]  sa[1~n]为有效值
     10 
     11 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
     12 
     13 //height:字典序排i和i-1的后缀的最长公共前缀  height[2~n]为有效值,第二个到最后一个
     14 
     15 const int INF=0x3f3f3f3f;
     16 const int maxn = 1e5+10;
     17 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
     18 int rnk[maxn],height[maxn],be[maxn];
     19 char s[maxn];
     20 int r[maxn],n,len,mx[maxn],mi[maxn];
     21 
     22 int cmp(int *r,int a,int b,int k)
     23 {
     24     return r[a]==r[b]&&r[a+k]==r[b+k];
     25 }
     26 
     27 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
     28 {
     29     int i,j,p,*x=wa,*y=wb,*t;
     30     for(i=0; i<m; i++)  wsf[i]=0;
     31     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
     32     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     33     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
     34     p=1;
     35     j=1;
     36     for(; p<=n; j*=2,m=p){
     37         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
     38         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
     39         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
     40         for(i=0; i<m; i++)  wsf[i]=0;
     41         for(i=0; i<=n; i++)  wsf[wv[i]]++;
     42         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     43         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
     44         swap(x,y);
     45         x[sa[0]]=0;
     46         for(p=1,i=1; i<=n; i++)
     47             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
     48     }
     49 }
     50 
     51 void getheight(int *r,int n)//n为添加0后的总长
     52 {
     53     int i,j,k=0;
     54     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
     55     for(i=0; i<n; i++){
     56         if(k)
     57             k--;
     58         else
     59             k=0;
     60         j=sa[rnk[i]-1];
     61         while(r[i+k]==r[j+k])
     62             k++;
     63         height[rnk[i]]=k;
     64     }
     65 }
     66 
     67 bool check(int k)
     68 {
     69     for(int j=0;j<n;j++) mx[j]=-INF,mi[j]=INF;      //一开始忘记初始化
     70     for(int i=2;i<=len;i++){
     71         if(height[i]>=k){
     72             mx[be[sa[i]]]=max(mx[be[sa[i]]],sa[i]);
     73             mi[be[sa[i]]]=min(mi[be[sa[i]]],sa[i]);
     74             mx[be[sa[i-1]]]=max(mx[be[sa[i-1]]],sa[i-1]);
     75             mi[be[sa[i-1]]]=min(mi[be[sa[i-1]]],sa[i-1]);       //没眼睛写成了sa[i]
     76         }
     77         else{
     78             int j=0;
     79             for(j=0;j<n;j++) mx[j]=-INF,mi[j]=INF;
     80             mx[be[sa[i]]]=sa[i],mi[be[sa[i]]]=sa[i];
     81         }
     82         int j=0;
     83         for(j=0;j<n;j++){
     84             if(mx[j]-mi[j]<k) break;
     85         }
     86         if(j==n) return true;
     87     }
     88     return false;
     89 }
     90 
     91 int main()
     92 {
     93     ios::sync_with_stdio(false);
     94     cin.tie(0);
     95     cout.tie(0);
     96     int t;
     97     cin>>t;
     98     while(t--){
     99         cin>>n;
    100         len=0;
    101         for(int i=0;i<n;i++){
    102             cin>>s+len;
    103             int p=strlen(s+len);
    104             for(int j=0;j<p;j++){
    105                 r[j+len]=s[j+len]-'a'+1;
    106                 be[len+j]=i;
    107             }
    108             len+=p;
    109             if(i!=n-1){
    110                 be[len]=i;
    111                 r[len++]=i+100;
    112             }
    113         }
    114         r[len]=0;
    115         getsa(r,sa,len,200);
    116         getheight(r,len);
    117         int l=0,r=min(len,10000);
    118         int ans=0;
    119         while(l<=r){
    120             int mid=l+r>>1;
    121             if(check(mid)){
    122                 ans=mid;
    123                 l=mid+1;
    124             }
    125             else r=mid-1;
    126         }
    127         cout<<ans<<endl;
    128     }
    129     return 0;
    130 }

    SPOJ - PHRASES

  • 相关阅读:
    用价值链分析软件开发及杂感
    《恰如其分的软件架构》笔记摘要
    观察者模式
    Js中Date对象
    Js中Currying的应用
    read命令
    模板方法模式
    两两交换链表中的节点
    享元模式
    Js中Array对象
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/12687197.html
Copyright © 2011-2022 走看看