Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
雁过留声http://codeforces.com/contest/452/problem/E https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3805 再推荐两道类似的题 解法都是 并查集 + 后缀数组 想法 其实用后缀树来做这题很轻松,只不过空间比较卡。 但我们可以借助于后缀树的思想用后缀数组来实现。 后缀树其实就是后缀字典树的压缩版而已,在考虑问题的时候完全可以用后缀字典树来想,很多问题就会变得非常简单, 比如这道题,以前是用单调栈来做的,不容易想啊, 现在假想我们已经建立好一颗后缀字典树, 那么答案就是字典树中所有深度大于等于k的节点的子树中两种叶子的数量相乘的和。两种叶子指的是两种后缀。 实现 我们建立后缀数组后,想象一下这样的结构,按照height数组划分区间, 一段区间被一个最小的height统治,然后两个子区间的最小的height又分别统治着两个子区间。 然后从大到小考虑height。如果长度为k的公共子串的数量是cnt,那么这个答案肯定也会加到k-1里面去。 我们对于height相同的所有的后缀一起考虑,其实就是后缀排序之后一段段连续的后缀,这些后缀的lcp是height。 将这些连续的后缀合并起来,答案会加上两种后缀的乘积。 写的时候可以写成两个后缀集合的合并,注意去重即可。 比如下面的例子 1:111111 2:111 3:11111 4:11 5:1111111 6:111 7:1111111 1 2 3后缀, 5 6 7后缀先各自合并,然后考虑到heigth为2时,肯定是 1~3后缀中的第一种后缀 * 5~7后缀中的第二种后缀 + 1~3后缀中的第二种后缀 * 5~7后缀中的第一种后缀 (只是描述个大概,能意会这种结构就能做了 代码也贴上来 #include <cstdio> #include <algorithm> #include <set> #include <cstring> #include <vector> #define wuyiqi const int MOD = 1000000007; const int N = 200610; int sa[N],X[N],Y[N],b[N],a[N],h[N],r[N]; bool comp(int *r,int a,int b,int le) { return r[a] == r[b] && r[a+le] == r[b+le]; } void sort(int *Rank,int *Id,int n,int m) { std::fill(b,b+m,0); for(int i = n-1; i >= 0; i--) b[Rank[i]]++; for(int i = 1; i < m; i++) b[i] += b[i-1]; for(int i = n-1; i >= 0; i--) sa[--b[Rank[Id[i]]]] = Id[i]; } void calh(int n) { for(int i = 1; i <= n; i++) r[sa[i]] = i; int height = 0; for(int i = 0; i < n; i++){ if(height) height--; int j = sa[r[i]-1]; while(a[j+height]==a[i+height]) height++; h[r[i]] = height; } } void suffix(int n,int m=500) { int *Rank = X, *Id = Y, p = 1; for(int i = 0; i < n; i++) Rank[i] = a[i], Id[i] = i; sort(Rank,Id,n,m); for(int j = 1; p < n; j <<= 1){ p = 0; for(int i = n-j; i < n; i++) Id[p++] = i; for(int i = 0; i < n; i++) if(sa[i] >= j) Id[p++] = sa[i] - j; sort(Rank,Id,n,p); std::swap(Rank,Id); Rank[sa[0]] = 0, p = 1; for(int i = 1; i < n; i++) Rank[sa[i]] = comp(Id,sa[i-1],sa[i],j) ? p-1 : p++; m = p; } calh(n-1); } char s[N]; std::vector<std::pair<int, int> > g[N]; int fa[N], cnt[N][2]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } int main() { int k; while(scanf("%d", &k), k) { int n = 0; memset(cnt, 0, sizeof(cnt)); for(int i = 0; i < 2; i++){ scanf("%s", s); for(int j = 0; s[j]; j++) { a[n++] = s[j]; cnt[n - 1][i] = 1; } if(!i) a[n++] = '$'; else a[n] = 0; } for(int i = 0; i <= n; i++) fa[i]=i,g[i].clear(); suffix(n + 1); h[n + 1] = 0; for(int i = 2; i <= n; i++) { g[h[i]].push_back(std::make_pair(sa[i], sa[i - 1])); } long long ret = 0, ans = 0; for(int i = n; i >= k; i--) { int sz = g[i].size(); for(int j = 0; j < sz; j++) { int suf_1 = g[i][j].first; int suf_2 = g[i][j].second; int rx = find(suf_1); int ry = find(suf_2); ret -= 1LL * cnt[rx][0] * cnt[rx][1]; ret -= 1LL * cnt[ry][0] * cnt[ry][1]; fa[ry] = rx; cnt[rx][0] += cnt[ry][0]; cnt[rx][1] += cnt[ry][1]; ret += 1LL * cnt[rx][0] * cnt[rx][1]; } ans += ret; } printf("%I64d\n", ans); } return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator