首页 > 代码库 > 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;
}
View Code

 

bzoj4199