首页 > 代码库 > bzoj4199
bzoj4199
http://www.lydsy.com/JudgeOnline/problem.php?id=4199
又做了一遍,感觉没什么难的,但是还是想了一下。。。
按lcp分类,从大到小合并,合并是按元素合并,就是lcp两端的sa,然后就行了,可能会有人想会不会导致将两个距离很远的sa合并,不会,因为按元素合并只会合并相邻的sa,不会合并隔着的sa,当两个sa合并时,他们肯定是相邻的,那么就好了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> PII; const int N = 300010; const ll inf = 1000000000000000010; int n; char c[N]; int s[N], x[N], a[N], b[N], rank[N], sa[N], fa[N]; ll ans1[N], ans2[N], mx[N], mn[N], size[N]; vector<PII> v[N]; void radix(int *s, int *a, int *b, int n, int m) { int count[N]; memset(count, 0, sizeof(count)); for(int i = 1; i <= n; ++i) ++count[s[a[i]]]; for(int i = 1; i <= m; ++i) count[i] += count[i - 1]; for(int i = n; i; --i) b[count[s[a[i]]]--] = a[i]; } void Sa() { for(int i = 1; i <= n; ++i) rank[i] = i; radix(s, rank, sa, n, 26); rank[sa[1]] = 1; for(int i = 2; i <= n; ++i) rank[sa[i]] = rank[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]); for(int k = 1; k <= n; k <<= 1) { for(int i = 1; i <= n; ++i) { a[i] = rank[i]; b[i] = i + k <= n ? rank[i + k] : 0; sa[i] = i; } radix(b, sa, rank, n, n); radix(a, rank, sa, n, n); rank[sa[1]] = 1; for(int i = 2; i <= n; ++i) rank[sa[i]] = rank[sa[i - 1]] + (a[sa[i]] != a[sa[i - 1]] || b[sa[i]] != b[sa[i - 1]]); } } void Lcp() { int h = 0; for(int i = 1; i <= n; ++i) rank[sa[i]] = i; for(int i = 1; i <= n; ++i) { int j = sa[rank[i] - 1]; fa[i] = i; mx[i] = mn[i] = x[i]; ans1[i] = -inf; ans2[i] = 0; size[i] = 1; if(rank[i] <= 1) continue; if(h > 0) --h; for(; i + h <= n && j + h <= n; ++h) if(s[i + h] != s[j + h]) break; v[h].push_back(make_pair(i, sa[rank[i] - 1])); } } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } void connect(int u, int v, int len) { int a = find(u), b = find(v); if(a == b) return; fa[b] = a; ans1[len] = max(ans1[len], max(mx[a] * mx[b], mn[a] * mn[b])); mx[a] = max(mx[a], mx[b]); mn[a] = min(mn[a], mn[b]); ans2[len] += size[a] * size[b]; size[a] += size[b]; } int main() { scanf("%d", &n); scanf("%s", c + 1); for(int i = 1; i <= n; ++i) s[i] = c[i] - ‘a‘ + 1; for(int i = 1; i <= n; ++i) scanf("%d", &x[i]); Sa(); Lcp(); for(int i = n - 1; i >= 0; --i) { if(i != n - 1) { ans1[i] = ans1[i + 1]; ans2[i] = ans2[i + 1]; } for(int j = 0; j < v[i].size(); ++j) connect(v[i][j].first, v[i][j].second, i); } for(int i = 0; i < n; ++i) printf("%lld %lld\n", ans2[i], ans1[i] == -inf ? 0 : ans1[i]); return 0; }
bzoj4199
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。