uva11107 后缀数组

题意给了n个串 然后计算 这些串中的子串在大于1/2的串中出现 求出这个串的最长长度。 将这些串用一个每出现的不同的字符拼起来 ,然后二分找lcp

#include <iostream>
#include <algorithm>
#include <string.h>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn=2005;
const int maxm=205;
const int MM=maxn*maxm;
struct SuffixArray
{
  int s[MM];      // 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)
  int sa[MM];     // 后缀数组
  int rank[MM];   // 名次数组. rank[0]一定是n-1,即最后一个字符
  int height[MM]; // height数组
  int t[MM], t2[MM], c[MM]; // 辅助数组
  int n; // 字符个数
     void clear(){ n=0; }
  void build(int m)
  {
      int *x=t,*y=t2,i;
      for(i=0; i<m; i++)c[i]=0;
      for(i=0; i<n; i++)c[ x[i] = s[i] ]++;
      for(i=1; i<m; i++)c[ i ] += c[ i-1 ];
     for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
      for(int k=1; k<=n; k<<=1)
      {
           int p=0;
           for(i=n-k; i<n; i++)y[p++]=i;
           for(i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
           for(i=0; i<m; i++)c[i]=0;
           for(i=0; i<n; i++)c[  x[y[ i] ] ]++;
           for(i=1; i<m; i++)c[i]+=c[i-1];
           for(i =n-1; i>=0; i--)sa[  --c[ x[ y[i] ]  ]  ] = y[i];
           swap(x,y);
           p=1;
           x[ sa[0] ] =0;
           for( i=1; i<n; i++) x[ sa[i] ]= y[ sa[i] ]==y[sa[i-1]] && y[ sa[i]+k ]== y[ sa[i-1] +k ]?p-1:p++;
           if(p>=n)break;
           m=p;
      }
  }
   void build_height() {
    int i,  k = 0;
    for(i = 0; i < n; i++) rank[sa[i]] = i;
    height[0]=0;
    for(i = 0; i < n; i++) {
      if(k) k--;
      if(rank[i]==0)continue;
      int j = sa[rank[i]-1];
      while(i+k<n&&j+k<n&&s[i+k] == s[j+k]) k++;
      height[rank[i]] = k;
    }
  }
}sa;
char word[MM];
int idx[MM],n,maxlen;
int flag[150];
void add(int ch, int i)
{
  idx[sa.n] = i;
  sa.s[sa.n++] = ch;
}
// 子串[L,R) 是否符合要求
bool good(int L, int R,int &ss)
{

  if(R - L <= n/2) return false;
  int cnt = 0;
  for(int i = L; i < R; i++) {
    int x = idx[sa.sa[i]];
    if(x != n && flag[x]!=ss) { flag[x] = ss; cnt++; }
  }
  return cnt > n/2;
}

void print_sub(int L, int R)
{
  for(int i = L; i < R; i++)
    printf("%c", sa.s[i] - 1 + ‘a‘);
  printf("\n");
}
int ss;
bool print_solutions(int len, bool print)
{
  int L = 0;
ss++;
  for(int R = 1; R <= sa.n; R++) {
    if(R == sa.n || sa.height[R] < len) { // 新开一段
      if(good(L, R,ss)) {
        if(print) print_sub(sa.sa[L], sa.sa[L] + len); else return true;
      }
      ss++;
      L = R;
    }
  }
  return false;
}

void solve(int maxlen)
{
  if(!print_solutions(1, false))
    printf("?\n");
  else {
    int L = 1, R = maxlen, M;
    while(L < R) {
      M = L + (R-L+1)/2;
      if(print_solutions(M, false)) L = M;
      else R = M-1;
    }
    print_solutions(L, true);
  }
}

int main()
{
    int kase=0;
    while(scanf("%d",&n)==1)
        {
             if(n==0)break;
             if(kase++>0) puts("");
               maxlen=0;
              sa.clear();
              for(int i=0; i<n; i++)
                {
                    scanf("%s",word);
                    int sz= strlen(word);
                    maxlen=max(sz,maxlen);
                    for(int j=0; j<sz; j++)
                        {
                            add(word[j]-‘a‘+1,i);
                        }
                    add(123+i,n);
                }
                add(123+n,n);
                if(n==1)printf("%s\n",word);
                else
                    {
                        ss=1;
                        memset(flag,0,sizeof(flag));
                        sa.build( 123+n+4 );
                        sa.build_height();
                        solve(maxlen);
                    }
        }
    return 0;
}

时间: 2024-10-09 00:44:09

uva11107 后缀数组的相关文章

UVA11107 后缀数组(new模板)

IT 要走多久,要怎么走. IT 要走多久,要怎么走.这些问题,在我已经快毕业了一个年头的现在,又重新浮现在我的脑海里.一边是工作的了了模块,一边是可以自己无聊打发的时间.这不是我当初要的路,现在的路是一条没有激情,没有波澜,没有变革,没有无论是技术方向,还是职业规划此时此刻又都摆在了我的眼前.工作是工作,职业是职业. 我一直这么觉得,我不想把IT仅仅当为一种工作一样继续这样做下去,我不喜欢把IT当成一种生存计生这样的做下去.它应该是我的一种爱好,一种职业,一种诉求,一种偏执,一种倔强的追求.而

【UVA11107 训练指南】Life Forms【后缀数组】

题意 输入n(n<=100)个字符串,每个字符串长度<=1000,你的任务是找出一个最长的字符串使得超过一半的字符串都包含这个字符串. 分析 训练指南上后缀数组的一道例题,据说很经典(估计也就是height分组比较常用).但是训练指南上给出的中文题面真滴坑B啊!书上说,连续出现,我懵逼了好久! 我们把这n个字符串连成一个长的字符串S,且中间用不同的未出现的字符相隔开(为什么隔开我们后面说),比如样例一会变为abcdefg1bcdefgh2cdefghi3.这样每一段是一个原字符串.然后问题转换

wenbao与后缀数组

倍增算法(da) 1 #define maxn 1000001 2 int wa[maxn],wb[maxn],wv[maxn],wss[maxn]; 3 4 int cmp(int *r, int a, int b, int l) { 5 return r[a] == r[b] && r[a+l] == r[b+l]; 6 } 7 8 void da(int *r, int *sa, int n, int m) { 9 int i, j, p, *x = wa, *y = wb, *t;

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【tyvj1860】后缀数组

描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0你的任务就是求出SA和height这两个数组.字符串长度<=200000 输入格式 一行,为描述中的字符串(仅会出现小写

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the