标签:
【题目大意】
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
【字符串hash的小笔记】
hash[i]=(hash[i-1]*p+idx(s[i]))%mod,idx为映射值,一般a..z映射1..26;
习惯上,p取一个6到8位的素数即可,mod一般取大素数 1e9+7(1000000007)或1e9+9(1000000009)。
hash[i]=(hash[i-1]*p+idx(s[i]))%mod 表示第 i 个前缀的hash值,是一个hash的前缀和,那么,要求S[l…r]这个子串的hash值:
hash[l..r]=(hash[r]-hash[l-1]*(p^(r-l+1)))%mod(假设字符串下标从1开始)
【思路】
据说是后缀自动机,然而蒟蒻并不会后缀自动机,所以硬着头皮用hash搞一搞。上次立了个flag,什么本年度最丑代码,这个才是吧……脑洞产物,绝非正解,能否过全看rp。
首先圆滚滚地把每一个单词的hash值求一下,然后快乐地开始二分公共子串的长度。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define mod 10000019 7 #define p 20011 8 using namespace std; 9 typedef long long ll; 10 const int MAXN=10; 11 const int MAXLEN=2000+50; 12 int n,minl; 13 ll hash[MAXN][MAXLEN]; 14 char str[MAXLEN]; 15 int len[MAXN]; 16 int vis[mod+1],times[mod+1]; 17 18 int check(int x) 19 { 20 memset(vis,0,sizeof(vis)); 21 memset(times,0,sizeof(times)); 22 ll mul=1; 23 for (int i=1;i<=x;i++) mul=(mul*p)%mod; 24 for (int i=1;i<=n;i++) 25 for (int j=x;j<=len[i];j++) 26 { 27 ll nowhash=(hash[i][j]-(hash[i][j-x]*mul)%mod+mod)%mod; 28 if (vis[nowhash]!=i) 29 { 30 times[nowhash]++; 31 vis[nowhash]=i; 32 if (times[nowhash]==n) return 1; 33 } 34 } 35 return 0; 36 } 37 38 void init() 39 { 40 minl=0x7fffffff; 41 scanf("%d",&n); 42 for (int i=1;i<=n;i++) 43 { 44 scanf("%s",str); 45 len[i]=strlen(str); 46 if (len[i]<minl) minl=len[i]; 47 hash[i][1]=str[0]-‘a‘+1; 48 49 for (int j=2;j<=len[i];j++) 50 hash[i][j]=(hash[i][j-1]*p+(str[j-1]-‘a‘+1))%mod; 51 } 52 } 53 54 void search_ans() 55 { 56 int lb=0,ub=minl+1; 57 while (lb<ub) 58 { 59 int mid=(lb+ub)>>1; 60 if (check(mid)) lb=mid+1;else ub=mid; 61 } 62 printf("%d",lb-1); 63 } 64 65 int main() 66 { 67 init(); 68 search_ans(); 69 return 0; 70 }
【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】
标签:
原文地址:http://www.cnblogs.com/iiyiyi/p/5701770.html