zoukankan      html  css  js  c++  java
  • BZOJ 3277 串 (广义后缀自动机)

    3277: 串
    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 309  Solved: 118
    [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
    

    算法讨论:

    首先对这些串建立出广义后缀自动机,同时在建立的时候要保存当前结点都是哪些串的子串,然后建立出Parent树,

    对树进行一遍DFS,把一个点的所以后代结点的颜色信息全部合并到自己身上,并用一个数组来维护当前结点有多少颜色,也就是多少个串的子串。

    因为我们知道,一个点在Parent树上的父亲结点是其的最长后缀,所以如果一个点有颜色Q,那么其所有祖先结点全部有颜色Q。

    然后对于每个串跑自动机,如果一个当前结点的颜色数目小于K,就沿其fail指针向上跳,跳到一个大于等于K的地方,

    此时答案应该加上min(这个点的len, 当前ln + 1的最小值)。 至于这个ln是做什么的,容我再想想。

    代码:

    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <set>
    #include <string>
     
    using namespace std;
    const int N = 100000 + 5;
    const int C = 26;
    typedef long long ll;
     
    int n, cnt, k;
    int head[N << 1], color[N << 1];
    string s[N];
    set <int> occ[N << 1];
    set <int> :: iterator it;
     
    struct State {
      int pre, len, next[C];
    }st[N << 1];
     
    struct SuffixAutomaton {
      int sz, last;
     
      void Init() {
        sz = last = 1;
        st[sz].pre = -1; st[sz].len = 0;
        sz ++;
      }
     
      void add(int c, int ccc) {
        int cur = sz ++, p;
        st[cur].len = st[last].len + 1;
        for(p = last; p != -1 && !st[p].next[c]; p = st[p].pre)
          st[p].next[c] = cur;
        if(p == -1) st[cur].pre = 1;
        else {
          int q = st[p].next[c];
          if(st[q].len == st[p].len + 1) st[cur].pre = q;
          else {
            int cle = sz ++;
            st[cle].pre = st[q].pre;
            st[cle].len = st[p].len + 1;
            for(int i = 0; i < C; ++ i) st[cle].next[i] = st[q].next[i];
            for(; p != -1 && st[p].next[c] == q; p = st[p].pre)
              st[p].next[c] = cle;
            st[q].pre = st[cur].pre = cle;
          }
        }
        last = cur;
        occ[cur].insert(ccc);
      }
    }sam;
     
    struct Edge {
      int from, to, next;
    }edges[N << 1];
     
    void insert(int from, int to) {
      ++ cnt;
      edges[cnt].from = from; edges[cnt].to = to;
      edges[cnt].next = head[from]; head[from] = cnt;
    }
     
    void dfs(int u) {
      for(int i = head[u]; i; i = edges[i].next) {
        int v = edges[i].to;
        dfs(v);
        if(occ[u].size() < occ[v].size())
          swap(occ[u], occ[v]);
        for(it = occ[v].begin(); it != occ[v].end(); ++ it)
          occ[u].insert(*it);
      }
      color[u] = occ[u].size();
    }
     
    int main() {
      //freopen("stringa.in", "r", stdin);
      //freopen("stringa.out", "w", stdout);
       
      int __size__ = 50 << 20;
      char *__p__ = (char*)malloc (__size__) + __size__;
      __asm__("movl %0, %%esp" :: "r"(__p__));
     
      //ios :: sync_with_stdio(false);
      cin >> n >> k;
      sam.Init();  
      for(int i = 1; i <= n; ++ i) {
        cin >> s[i];
        int len = s[i].length();
        for(int j = 0; j < len; ++ j) sam.add(s[i][j] - 'a', i);
        sam.last = 1;
      }
      for(int i = 1; i < sam.sz; ++ i)
        if(st[i].pre != -1) insert(st[i].pre, i);
      dfs(1);
      for(int i = 1; i <= n; ++ i) {
        if(k > n) { cout << 0 << " "; continue; }
        ll ans = 0;
        int p = 1, ln = 0, len;
        len = s[i].length();
        for(int j = 0; j < len; ++ j) {
          p = st[p].next[(int) s[i][j] - 'a'];
          while(color[p] < k) p = st[p].pre;
          ln = min(ln + 1, st[p].len);
          ans += ln;
        }
        cout << ans << " ";
      }
     
      //fclose(stdin); fclose(stdout);
      return 0;
    }
    
  • 相关阅读:
    KMP总结
    条件概率的计算
    EL和JSTL
    tomcat部署web项目
    web
    面试1
    面试可能会问的题
    简介
    建一个springboot项目
    刷题之牛客网
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5396315.html
Copyright © 2011-2022 走看看