【BZOJ】【2946】【POI2000】公共串

后缀数组



  好感动,复习了下后缀数组居然写出来了……(感谢ykz大神)

  求最长公共子串……WA了一发是因为:【不同字符串之间要用不同的特殊字符隔开】否则就会匹配到相同→_→比如都是aaa结尾,如果用相同特殊字符就会使得最长公共子串变成aaa#这样子……

  1 /**************************************************************
  2     Problem: 2946
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:60 ms
  7     Memory:4104 kb
  8 ****************************************************************/
  9
 10 //BZOJ 2946
 11 #include<vector>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<iostream>
 16 #include<algorithm>
 17 #define rep(i,n) for(int i=0;i<n;++i)
 18 #define F(i,j,n) for(int i=j;i<=n;++i)
 19 #define D(i,j,n) for(int i=j;i>=n;--i)
 20 #define pb push_back
 21 using namespace std;
 22 typedef long long LL;
 23 inline int getint(){
 24     int r=1,v=0; char ch=getchar();
 25     for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘)r=-1;
 26     for(; isdigit(ch);ch=getchar()) v=v*10+ch-‘0‘;
 27     return r*v;
 28 }
 29 const int N=1e5+10,INF=~0u>>2;
 30 /*******************template********************/
 31 int sa[N],rank[N],height[N],belong[N],wa[N],wb[N],c[N],n,m;
 32 int len[6];
 33 char s[N];
 34 bool cmp(int *r,int a,int b,int l){
 35     return r[a]==r[b] && r[a+l]==r[b+l];
 36 }
 37 void DA(char *s,int *sa,int n,int m){
 38     int i,j,p,*x=wa,*y=wb;
 39     rep(i,m) c[i]=0;
 40     rep(i,n) c[x[i]=s[i]]++;
 41     F(i,1,m-1) c[i]+=c[i-1];
 42     D(i,n-1,0) sa[--c[x[i]]]=i;
 43     for(j=1,p=0;p<n;j<<=1,m=p){
 44         for(p=0,i=n-j;i<n;i++) y[p++]=i;
 45         rep(i,n) if (sa[i]>=j) y[p++]=sa[i]-j;
 46
 47         rep(i,m) c[i]=0;
 48         rep(i,n) c[x[y[i]]]++;
 49         F(i,1,m-1) c[i]+=c[i-1];
 50         D(i,n-1,0) sa[--c[x[y[i]]]]=y[i];
 51         swap(x,y); p=1; x[sa[0]]=0;
 52         F(i,1,n-1) x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1 : p++;
 53     }
 54 }
 55 void calheight(char *s,int *sa,int n){
 56     int k=0;
 57     F(i,1,n) rank[sa[i]]=i;
 58     rep(i,n){
 59         if (k) k--;
 60         int j=sa[rank[i]-1];
 61         while(s[i+k]==s[j+k]) k++;
 62         height[rank[i]]=k;
 63     }
 64 }
 65 int main(){
 66 #ifndef ONLINE_JUDGE
 67     freopen("2946.in","r",stdin);
 68     freopen("2946.out","w",stdout);
 69 #endif
 70     n=getint();int l=0;
 71     F(i,1,n){
 72         scanf("%s",s+l);
 73         len[i]=strlen(s)-l;
 74         l=strlen(s);
 75         s[l++]=‘a‘-n+i;
 76     }
 77     rep(i,l) s[i]=s[i]-‘a‘+10;
 78     l--;
 79     DA(s,sa,l+1,40);
 80     calheight(s,sa,l);
 81     int tmp=1;
 82     rep(i,l){
 83         if (s[i]<10) {tmp++;continue;}
 84         belong[rank[i]]=tmp;
 85     }
 86
 87
 88     bool vis[6]={0};
 89     int L=0,R=2000,mid,cnt,ans=0;
 90     while(L<=R){
 91         mid=(L+R)>>1;bool sign=0;
 92         cnt=0; memset(vis,0,sizeof vis);
 93         F(i,n,l){
 94             if (height[i]<mid){
 95                 cnt=1;memset(vis,0,sizeof vis);
 96                 vis[belong[i]]=1; continue;
 97             }
 98             if (!vis[belong[i]]) vis[belong[i]]=1,cnt++;
 99             if (cnt==n) sign=1;
100         }
101         if (sign) ans=mid,L=mid+1;
102         else R=mid-1;
103     }
104     printf("%d\n",ans);
105     return 0;
106 }

2946: [Poi2000]公共串

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 160  Solved: 67
[Submit][Status][Discuss]

Description

给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

任务:

l        读入单词

l        计算最长公共子串的长度

l        输出结果

Input

文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

Output

仅一行,一个整数,最长公共子串的长度。

Sample Input

3
abcb
bca
acbc

Sample Output

HINT

Source

[Submit][Status][Discuss]

时间: 2024-10-05 13:10:59

【BZOJ】【2946】【POI2000】公共串的相关文章

BZOJ 2946 Poi2000 公共串 后缀自动机

题目大意:求n个串的最长公共子串 太久没写SAM了真是-- 将第一个串建成后缀自动机,用其它的串进去匹配 每个节点记录每个串在上面匹配的最大长度 那么这个节点对答案的贡献就是所有最大长度的最小值 对所有贡献取最大就行了= = 这最大最小看着真是别扭 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10100 using namesp

BZOJ 2946: [Poi2000]公共串

Description 最长公共子串,\(n\leqslant 5,l\leqslant 1000\) Solution SAM... 对于同一字符串取max,不用字符串取min Code /************************************************************** Problem: 2946 User: BeiYu Language: C++ Result: Accepted Time:1012 ms Memory:2308 kb ******

BZOJ 2946 POI2000 公共串 后缀自动机(多串最长公共子串)

题意概述:给出N个字符串,每个串的长度<=2000(雾...可能是当年的年代太久远机子太差了),问这N个字符串的最长公共子串长度为多少.(N<=5) 抛开数据结构,先想想朴素做法. 设计一种稳定的暴力算法.可以想到这样一种做法:首先确定一个串,枚举每个位置,然后暴力计算其他每个串以这个位置开头的最长匹配,取最小值,就是在公共子串在我们确定下来的串的这个位置开头的时候所能得到的最长公共子串.不难发现把这个问题转化成后缀的形式也是一样的.同时发现可能在枚举多个位置的时候答案甚至最后构造出来的串都是

【BZOJ】2946: [Poi2000]公共串

http://www.lydsy.com/JudgeOnline/problem.php?id=2946 题意:给n个串,求最大公共子串.(1<=n<=5,每个串长度<=2000) #include <bits/stdc++.h> using namespace std; const int N=2005<<1; struct sam { int cnt, root, last, l[N], c[N][26], f[N], p[N], mx[N], mxl[N];

[BZOJ2946][Poi2000]公共串 后缀自动机

2946: [Poi2000]公共串 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1367  Solved: 612[Submit][Status][Discuss] Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单词 l        计算最长公共子串的长度 l        输出结果 Input 文件的第一行是整数 n,1<=n<=5,表示单词的数量.接下来n行每行一个单词

[BZOJ2946] [Poi2000]公共串解题报告|后缀数组

给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 单词个数<=5,每个单词长度<=2000 尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA... (其实是不知道应该怎么用SAM做... 对于后缀数组而言,多个字符串的公共子串与两个处理起来并没有什么区别 只要在中间加一些没有用的字符,将多个字符串拼成一个字符串 然后二分答案,对于一个长度L,在一组除了开头其他height都>=L的区间中如果每个字符串的位置都出现过就可以 应该是第二次这么解决一道公共串的题了.. 然

[Poi2000]公共串

1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <cstring> 6 #define maxn 4005 7 #define maxm 2005 8 using namespace std; 9 10 int n,m,tot,last,root,len,smin[maxn],sum[maxn],tmp[m

[Poi2000]公共串 &amp;&amp; hustoj2797

传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2797 题目大意:给你几个串求出几个串中的最长公共子串. 题解:先看n最大才5,所以很容易想到暴力写法,因为最近在学后缀自动机就写写后缀自动机吧. 我们将第一个串作为母串,然后在用其他的串与它进行匹配,并且记录下其匹配中每个状态的最大匹配数,答案则为每个状态的最大匹配的最小值中的最大值..(绕晕了) 1 #include<iostream> 2 #include<algorith

[POI2000]公共串 - 后缀数组

Description 求若干个串的最长的公共子串的长度. Solution 考虑将这若干个串全部拼起来,中间用一些不在字符集内的符号隔开. 然后二分答案 \(K\),如果连续的一段 \(height\) 都大于等于 \(K\),且每个串都出现了至少一次,则是可行的. Code #include <bits/stdc++.h> using namespace std; const int _ = 1e5 + 10; int N, n, s[_], belong[_]; int rnk[_],

BZOJ2946: [Poi2000]公共串

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2946 先用第一个字符串建后缀自动机,每个节点记录一下每个字符串与之匹配的最大值,那么每个节点对答案的贡献就是所记录的最大值的最小值,把所有刚刚说的最小值取max就是答案了.绕晕了.语文不好真是日了狗. 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define inf 1<&l