3145: [Feyat cup 1.5]Str
2017-01-29 23:44
274 查看
3145: [Feyat cup 1.5]Str
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 142 Solved: 25
[Submit][Status][Discuss]
Description
Arcueid,白姬,真祖的公主。在和推倒贵看电影时突然对一个问题产生了兴趣:我们都知道真祖和死徒是有类似的地方。那么从现代科学的角度如何解释
呢?自然就得研究遗传密码了。Arcueid得知了两者的DNA片段,想寻求一个
DNA片段,使得其在两者的DNA中都出现过。
我们知道公主的脑袋有点不太灵活,如果两个DNA片段只有一个位置不
同,她也会将其认为是相同的。所以请您找出这样的最长的DNA片段吧。
Input
两行,每行一个字符串。Output
一个整数,表示最长的 DNA 片段的长度。Sample Input
aabbeacbbc
Sample Output
4HINT
100% 的数据 n<=10^5;m<=10^5 。每个串中只包含小写字母(别问我为什么不是 ATCG )。
Source
Hza 提供[Submit][Status][Discuss]
假设最优方案中,A串第i个位置和B串第j个位置被选为不等的位置
那么,对(i-1,j-1)求个lcs,对(i+1,j+1)求个lcp,这样三部分结合就是答案了
可以枚举点对(i,j),然后用hash...bulabulabula...O(n^2logn)
对于两个串,分别在它们的头尾都填上一个奇怪的字符,一共四个,四个都不一样
然后将两个串接起来,求个sam,这样,sam每个点的right集里的点的组合,lcp就是当前点的len
[b]对于拼接串,再求个sa,得到height[/b]
为了求lcs,不妨每个点打个标记,就是它所属位置+2的rank(这就是为什么添加奇怪字符)
最后,在sam上用线段树合并,不断更新即可
就是线段树维互right集合内任意两点组合的lcs最大值
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector> using namespace std; const int maxn = 2E5 + 20; const int maxm = maxn * 2; const int T = 20; const int INF = ~0U>>1; int n1,n2,N,Ans,cnt,tot,last,Cnt,root,height[maxn],sa[maxn],rank[maxn],t[maxn],t2[maxn],c[maxn],ch[maxm][30],LEN[maxm],fail[maxm] ,rt[maxm],lc[maxn*T],rc[maxn*T],Left[maxn*T][2],Right[maxn*T][2],Max[maxn*T],Min[maxn][T],bin[maxn],len[maxn],pos[maxn]; char s[maxn],A[maxn],B[maxn]; vector <int> v[maxm]; void Work(int *height,int *sa,int *rank) { int *x = t,*y = t2,m = 30; for (int i = 1; i <= m; i++) c[i] = 0; for (int i = 1; i <= N; i++) ++c[x[i] = s[i] + 1]; for (int i = 1; i <= m; i++) c[i] += c[i-1]; for (int i = N; i; i--) sa[c[x[i]]--] = i; for (int k = 1; k < N; k <<= 1) { int p = 0; for (int i = N; i > N - k; i--) y[++p] = i; for (int i = 1; i <= N; i++) if (sa[i] > k) y[++p] = sa[i] - k; for (int i = 1; i <= m; i++) c[i] = 0; for (int i = 1; i <= N; i++) ++c[x[i]]; for (int i = 2; i <= m; i++) c[i] += c[i-1]; for (int i = N; i; i--) sa[c[x[y[i]]]--] = y[i]; swap(x,y); p = 1; x[sa[1]] = 1; for (int i = 2; i <= N; i++) x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p : ++p; m = p; if (m == N) break; } int k = 0; for (int i = 1; i <= N; i++) rank[sa[i]] = i; for (int i = 1; i <= N; i++) { if (k) --k; int j = sa[rank[i] - 1]; while (s[i + k] == s[j + k]) ++k; height[rank[i]] = k; } /*for (int i = 1; i <= N; i++) putchar(s[i] + 'a'); puts(""); for (int i = 1; i <= N; i++) { for (int j = sa[i]; j <= N; j++) putchar(s[j] + 'a'); printf(" %d\n",height[i]); }*/ } int Extend(int Nex,int le) { int p = last,np = ++Cnt; last = np; LEN[np] = le; while (p && !ch[p][Nex]) ch[p][Nex] = np,p = fail[p]; if (!p) {fail[np] = root; return np;} int q = ch[p][Nex]; if (LEN[q] - LEN[p] == 1) fail[np] = q; else { int nq = ++Cnt; LEN[nq] = LEN[p] + 1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fail[nq] = fail[q]; fail[q] = fail[np] = nq; while (p && ch[p][Nex] == q) ch[p][Nex] = nq,p = fail[p]; } return np; } int Insert(int l,int r,int pos,int typ) { int ret = ++cnt; Max[ret] = -INF; Left[ret][typ] = Right[ret][typ] = pos; Left[ret][typ^1] = INF; Right[ret][typ^1] = 0; if (l == r) return ret; int mid = (l + r) >> 1; if (pos <= mid) lc[ret] = Insert(l,mid,pos,typ); else rc[ret] = Insert(mid+1,r,pos,typ); return ret; } int RMQ(int l,int r) { ++l; int k = r - l + 1; return min(Min[l][bin[k]],Min[r - len[k] + 1][bin[k]]); } int Merge(int o1,int o2,int l,int r) { if (!o1) return o2; if (!o2) return o1; int mid = (l + r) >> 1; Max[o1] = -INF; lc[o1] = Merge(lc[o1],lc[o2],l,mid); rc[o1] = Merge(rc[o1],rc[o2],mid+1,r); for (int i = 0; i < 2; i++) { Left[o1][i] = min(Left[lc[o1]][i],Left[rc[o1]][i]); Right[o1][i] = max(Right[lc[o1]][i],Right[rc[o1]][i]); } Max[o1] = max(Max[lc[o1]],Max[rc[o1]]); if (lc[o1] && rc[o1]) { if (Right[lc[o1]][0] != 0 && Left[rc[o1]][1] != INF) Max[o1] = max(Max[o1],RMQ(Right[lc[o1]][0],Left[rc[o1]][1])); if (Right[lc[o1]][1] != 0 && Left[rc[o1]][0] != INF) Max[o1] = max(Max[o1],RMQ(Right[lc[o1]][1],Left[rc[o1]][0])); } return o1; } void Dfs(int x) { for (int i = 0; i < v[x].size(); i++) { int to = v[x][i]; Dfs(to); rt[x] = Merge(rt[x],rt[to],1,N); } if (Max[rt[x]] != -INF) Ans = max(Ans,Max[rt[x]] + LEN[x]); } int main() { #ifdef DMC freopen("DMC.txt","r",stdin); #endif scanf("%s",A + 1); n1 = strlen(A + 1); scanf("%s",B + 1); n2 = strlen(B + 1); s[tot = 1] = 26; for (int i = 1; i <= n1; i++) s[++tot] = A[i] - 'a'; s[++tot] = 27; s[++tot] = 28; for (int i = 1; i <= n2; i++) s[++tot] = B[i] - 'a'; s[++tot] = 29; s[0] = s[tot+1] = 30; N = n1 + n2 + 4; Work(height,sa,rank); root = last = Cnt = 1; for (int i = 1; i <= N; i++) pos[i] = Extend(s[i],i); for (int i = 1; i <= N; i++) { bin[i] = (1 << bin[i-1] + 1) < i ? bin[i-1] + 1 : bin[i-1]; len[i] = (1 << bin[i]); Min[i][0] = height[i]; } for (int j = 1; j < T; j++) for (int i = 1; i <= N; i++) { int Nex = i + (1 << j - 1); if (Nex > N) break; Min[i][j] = min(Min[i][j-1],Min[Nex][j-1]); } Left[0][0] = Left[0][1] = INF; Max[0] = -INF; for (int i = 2; i <= Cnt; i++) v[fail[i]].push_back(i); for (int i = 2; i <= n1 + 1; i++) rt[pos[i-1]] = Insert(1,N,rank[i+1],0); for (int i = 2; i <= n2 + 1; i++) rt[pos[i-1+n1+2]] = Insert(1,N,rank[i+1+n1+2],1); Dfs(root); cout << Ans + 1 << endl; return 0; }
对于拼接串,再求个sa,得到height
相关文章推荐
- Bzoj 3145 - [Feyat cup 1.5]Str
- [BZOJ 3145][Feyat cup 1.5]Str 解题报告
- BZOJ3145 : [Feyat cup 1.5]Str
- 第13周项目1.5 插入一个数到a[0]位置
- MATLAB double、str、cell间的类型转换
- careercup-数组和字符串1.5
- 第十六周项目 2 用指针玩字符串——去除str中的特定字符
- 第十六周项目二:用指针玩字符串(2):去除字符串str中的特定字符c
- String str 与 String str=new String("") 区别
- python 编码unicode 和 str
- str' object is not callable
- 【采集】php str_replace
- 编写一个函数 int count_chars(char const *str,char const *chars) 函数应该在第一个参数中进行查找, 并返回匹配第二个参数所包含的字符的数量。
- PHP str_replace() 函数
- STR STD 详解
- Java入门到精通——调错篇之Spring2.5使用AOP时报错only available on JDK 1.5 and higher
- TCPIP详解第1卷1.3TCPIP分层1.4互联网的地址1.5域名系统1.6封装
- DataUml Design 介绍11 - DataUML 1.5版本功能-支持无Oracle客户端
- target release 1.5 conflicts with default source release 1.7
- python-str方法使用