• POJ


    传送门:POJ - 1226

    这个题跟POJ - 3294  和POJ - 3450 都是一样的思路,一种题型。

    POJ - 3294的题解可以见:https://www.cnblogs.com/lilibuxiangtle/p/12649853.html

    题意:给你n个字符串,求最长子串的长度,要求子串或子串的翻转串在n个字符串中都出现。

    题解:把每个字符串和字符串的翻转串连接起来,中间用不同且没出现过的字符隔开,然后再把n个字符串和翻转的串连到一起。然后后缀数组求出sa数组和height数组,用be数组标记每个位置的字符在哪个串中。二分长度,vis数组标记符合条件的串,cnt记录个数,如果cnt>=n则说明该长度可以,反之则不行。(重点!!vis及时标记 我憨憨的wa了好几发,找了快三个小时

      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];
     19 char s[maxn];
     20 int r[maxn],n,L;
     21 int be[maxn],vis[110];
     22 
     23 int cmp(int *r,int a,int b,int k)
     24 {
     25     return r[a]==r[b]&&r[a+k]==r[b+k];
     26 }
     27 
     28 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
     29 {
     30     int i,j,p,*x=wa,*y=wb,*t;
     31     for(i=0; i<m; i++)  wsf[i]=0;
     32     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
     33     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     34     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
     35     p=1;
     36     j=1;
     37     for(; p<=n; j*=2,m=p){
     38         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
     39         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
     40         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
     41         for(i=0; i<m; i++)  wsf[i]=0;
     42         for(i=0; i<=n; i++)  wsf[wv[i]]++;
     43         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     44         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
     45         swap(x,y);
     46         x[sa[0]]=0;
     47         for(p=1,i=1; i<=n; i++)
     48             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
     49     }
     50 }
     51 
     52 void getheight(int *r,int n)//n为添加0后的总长
     53 {
     54     int i,j,k=0;
     55     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
     56     for(i=0; i<n; i++){
     57         if(k)
     58             k--;
     59         else
     60             k=0;
     61         j=sa[rnk[i]-1];
     62         while(r[i+k]==r[j+k])
     63             k++;
     64         height[rnk[i]]=k;
     65     }
     66 }
     67 
     68 bool check(int k)
     69 {
     70     memset(vis,0,sizeof(vis));
     71     int cnt=0;
     72     for(int i=2;i<=L;i++){
     73         if(height[i]>=k){
     74             if(!vis[be[sa[i]]]) cnt++;
     75             vis[be[sa[i]]]=1;               //就是这个地方卡了我快3个小时!!!
     76             if(!vis[be[sa[i-1]]]) cnt++;
     77             vis[be[sa[i-1]]]=1;
     78         }
     79         else {
     80             memset(vis,0,sizeof(vis));
     81             cnt=0;
     82         }
     83         if(cnt>=n) return 1;
     84     }
     85     return 0;
     86 }
     87 
     88 int main()
     89 {
     90     ios::sync_with_stdio(false);
     91     cin.tie(0);
     92     cout.tie(0);
     93     int t;
     94     cin>>t;
     95     while(t--){
     96         cin>>n;
     97         L=0;
     98         for(int i=0;i<n;i++){
     99             cin>>s;
    100             int len=strlen(s);
    101             for(int j=0;j<len;j++){
    102                 r[L]=s[j];
    103                 be[L++]=i;
    104             }
    105             r[L]=i+200;
    106             be[L++]=i;
    107             for(int j=len-1;j>=0;j--){
    108                 r[L]=s[j];
    109                 be[L++]=i;
    110             }
    111             if(i!=n-1) r[L]=i+n+200,be[L++]=i;
    112         }
    113         if(n==1) {
    114             cout<<strlen(s)<<endl;
    115             continue;
    116         }
    117         r[L]=0;
    118         getsa(r,sa,L,500);
    119         getheight(r,L);
    120         int l=0,r=105,ans=0;
    121         while(l<=r){
    122             int mid=l+r>>1;
    123             if(check(mid)) ans=mid,l=mid+1;
    124             else r=mid-1;
    125         }
    126         cout<<ans<<endl;
    127     }
    128     return 0;
    129 }
  • 相关阅读:
    学习:类和对象——继承
    学习:类和对象——运算符重载
    域权限维持:Skeleton Key
    域权限维持:SSP密码记录
    学习:类和对象——友元
    学习:类和对象——对象模型和this指针
    学习:类和对象——静态成员变量和函数
    学习:类和对象——初始化列表和内部类
    学习:类和对象——深拷贝和浅拷贝
    二维数组中的查找
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/12691540.html
Copyright © 2020-2023  润新知