zoukankan      html  css  js  c++  java
  • BZOJ 3277: 串/ BZOJ 3473: 字符串 ( 后缀数组 + RMQ + 二分 )

    CF原题(http://codeforces.com/blog/entry/4849, 204E), CF的解法是O(Nlog^2N)的..记某个字符串以第i位开头的字符串对答案的贡献f(i), 那么f(i-1)>=f(i)-1, 然后就是O(NlogN)了, 但是速度垫底了....被后缀自动机完爆了...

    ----------------------------------------------------------------------------------------------

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
    #define b(x) (1 << (x))
     
    const int maxn = 200009;
     
    int Sa[maxn], Rank[maxn], Height[maxn], S[maxn], cnt[maxn];
    int L[maxn], R[maxn], Id[maxn]; // [L, R)
    int buf[20], Pos[maxn], mn[20][maxn], K, N, n;
    char str[maxn];
     
    void Init() {
    n = 0;
    scanf("%d%d", &N, &K);
    for(int i = 0; i < N; i++) {
    scanf("%s", str);
    L[i] = n;
    for(int j = 0, g = strlen(str); j < g; j++) {
    Id[n] = i;
    S[n++] = str[j] - 'a' + 1;
    }
    R[i] = n;
    Id[n] = N;
    S[n++] = 0;
    }
    }
     
    void Build() {
    int m = 30, *x = Height, *y = Rank;
    for(int i = 0; i < m; i++) cnt[i] = 0;
    for(int i = 0; i < n; i++) cnt[x[i] = S[i]]++;
    for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
    for(int i = 0; i < n; i++) Sa[--cnt[x[i]]] = i;
    for(int k = 1, p = 0; k <= n; k <<= 1, p = 0) {
    for(int i = n - k; i < n; i++) y[p++] = i;
    for(int i = 0; i < n; i++)
    if(Sa[i] >= k) y[p++] = Sa[i] - k;
    for(int i = 0; i < m; i++) cnt[i] = 0;
    for(int i = 0; i < n; i++) cnt[x[y[i]]]++;
    for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
    for(int i = n; i--; ) Sa[--cnt[x[y[i]]]] = y[i];
    swap(x, y);
    p = 1;
    x[Sa[0]] = 0;
    for(int i = 1; i < n; i++) {
    if(y[Sa[i]] != y[Sa[i - 1]] || y[Sa[i] + k] != y[Sa[i - 1] + k]) p++;
    x[Sa[i]] = p - 1;
    }
    if(p >= n) break;
    m = p;
    }
    for(int i = 0; i < n; i++) Rank[Sa[i]] = i;
    Height[0] = 0;
    for(int i = 0, h = 0; i < n; i++) if(Rank[i]) {
    if(h) h--;
    while(S[i + h] == S[Sa[Rank[i] - 1] + h]) h++;
    Height[Rank[i]] = h;
    }
    }
     
    void Init_RMQ() {
    for(int i = 0; i < n; i++) mn[0][i] = Height[i];
    for(int i = 1; b(i) <= n; i++)
    for(int j = 0; j + b(i) <= n; j++)
    mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + b(i - 1)]);
    }
     
    inline int RMQ(int l, int r) {
    if(r < l) return maxn;
    int t = log2(r - l + 1);
    return min(mn[t][l], mn[t][r - b(t) + 1]);
    }
     
    bool chk(int x, int len) {
    int _L, _R;
    if(Height[x] >= len) {
    int l = 1, r = x;
    while(l <= r) {
    int m = (l + r) >> 1;
    if(RMQ(m, x) >= len)
    _L = m - 1, r = m - 1;
    else
    l = m + 1;
    }
    } else
    _L = x;
    if(x + 1 < n && Height[x + 1] >= len) {
    int l = x, r = n - 1;
    while(l <= r) {
    int m = (l + r) >> 1;
    if(RMQ(x + 1, m) >= len)
    _R = m, l = m + 1;
    else
    r = m - 1;
    }
    } else
    _R = x;
    return ~Pos[_R] && Pos[_R] >= _L;
    }
     
    void Work() {
    Build();
    for(int i = 0; i < N; i++) cnt[i] = 0;
    cnt[N] = N;
    for(int i = 0, p = 0, tot = 0; i < n; i++) {
    if(!cnt[Id[Sa[i]]]) tot++;
    cnt[Id[Sa[i]]]++;
    while(tot > K || (tot == K && cnt[Id[Sa[p]]] > 1))
    if(!--cnt[Id[Sa[p++]]]) tot--;
    if(tot >= K) {
    Pos[i] = p;
    } else
    Pos[i] = -1;
    }
    Init_RMQ();
    for(int i = 0; i < N; i++) {
    ll tot = 0;
    for(int j = L[i], Last = 0; j < R[i]; j++) {
    int ans = max(Last - 1, 0);
    while(ans < R[i] - j && chk(Rank[j], ans + 1)) ans++;
    Last = ans;
    tot += ans;
    }
    printf("%I64d ", tot);
    }
    puts("");
    }
     
    int main() {
    Init();
    Work();
    return 0;
    }

    ----------------------------------------------------------------------------------------------

    3277: 串

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 284  Solved: 108
    [Submit][Status][Discuss]

    Description

    字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)。

    Input

    第一行两个整数n,k。
      接下来n行每行一个字符串。

    Output

     
    输出一行n个整数,第i个整数表示第i个字符串的答案。

    Sample Input


    3 1
    abc
    a
    ab

    Sample Output

    6 1 3

    HINT

    对于100%的数据,n,k,l<=100000

    Source

  • 相关阅读:
    IOS-UI基础-图片浏览器
    IOS-UI基础-UIImageView帧动画
    IOS-UI-transform
    IOS-UI基础-按钮扩展
    IOS-UI基础-UIView和UIViewController
    IOS-UI基础-按钮
    OC-关于COPY关键字
    OC-NSNumber与NSValue
    OC-NSFileManager创建目录
    2019规划目标
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5143361.html
Copyright © 2011-2022 走看看