zoukankan      html  css  js  c++  java
  • bzoj3473 字符串

    双倍经验:bzoj3277

    题意:给定n个字符串,对于每个字符串,求有多少个非空子串是其中至少k个字符串的子串。

    解:有一种毒瘤后缀数组解法...不过后缀自动机吊打后缀树组!耶~

    广义后缀自动机。

    先建出来,然后对于每个串,跑一遍后缀自动机。我们试图把该串的所有子串都打上标记(sum++)。

    跑到的每个节点,都代表一个前缀,我们跳fail就能得到该前缀的所有后缀。用vis数组避免重复标记。

    所有sum >= k的节点,贡献为len - len[fail],否则为0。

    之后对于每个串再跑后缀自动机,跑到的每个节点的贡献为它到根的贡献,可以预处理出来,加起来就是答案。

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <string>
      5 
      6 const int N = 500010;
      7 
      8 struct Edge {
      9     int nex, v;
     10 }edge[N << 1]; int top;
     11 
     12 int tr[N][26], len[N], cnt[N], sum[N], fail[N], vis[N];
     13 int last = 1, tot = 1, Time, k, e[N];
     14 std::string str[100010];
     15 char s[N];
     16 
     17 inline void add(int x, int y) {
     18     top++;
     19     edge[top].v = y;
     20     edge[top].nex = e[x];
     21     e[x] = top;
     22     return;
     23 }
     24 
     25 inline int split(int p, int f) {
     26     int Q = tr[p][f], nQ = ++tot;
     27     len[nQ] = len[p] + 1;
     28     fail[nQ] = fail[Q];
     29     fail[Q] = nQ;
     30     memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
     31     while(tr[p][f] == Q) {
     32         tr[p][f] = nQ;
     33         p = fail[p];
     34     }
     35     return nQ;
     36 }
     37 
     38 inline int insert(int p, char c) {
     39     int f = c - 'a';
     40     if(tr[p][f]) {
     41         int Q = tr[p][f];
     42         if(len[Q] == len[p] + 1) {
     43             return Q;
     44         }
     45         return split(p, f);
     46     }
     47     int np = ++tot;
     48     len[np] = len[p] + 1;
     49     while(p && !tr[p][f]) {
     50         tr[p][f] = np;
     51         p = fail[p];
     52     }
     53     if(!p) {
     54         fail[np] = 1;
     55     }
     56     else {
     57         int Q = tr[p][f];
     58         if(len[Q] == len[p] + 1) {
     59             fail[np] = Q;
     60         }
     61         else {
     62             fail[np] = split(p, f);
     63         }
     64     }
     65     return np;
     66 }
     67 
     68 void DFS(int x) {
     69     if(vis[x] == Time || !x) {
     70         return;
     71     }
     72     sum[x]++;
     73     vis[x] = Time;
     74     DFS(fail[x]);
     75     return;
     76 }
     77 
     78 void DFS_1(int x) {
     79     cnt[x] = cnt[fail[x]] + (len[x] - len[fail[x]]) * (sum[x] >= k);
     80     //printf("cnt %d = %d + %d * %d 
    ", x, cnt[fail[x]], len[x] - len[fail[x]], sum[x] >= k);
     81     for(int i = e[x]; i; i = edge[i].nex) {
     82         int y = edge[i].v;
     83         DFS_1(y);
     84     }
     85     return;
     86 }
     87 
     88 int main() {
     89     int n;
     90     scanf("%d%d", &n, &k);
     91     for(int i = 1; i <= n; i++) {
     92         scanf("%s", s);
     93         int t = strlen(s);
     94         last = 1;
     95         for(int j = 0; j < t; j++) {
     96             last = insert(last, s[j]);
     97         }
     98         str[i] = (std::string)(s);
     99     }
    100 
    101     for(int i = 1; i <= n; i++) {
    102         int p = 1, t = str[i].size();
    103         Time = i;
    104         for(int j = 0; j < t; j++) {
    105             int f = str[i][j] - 'a';
    106             p = tr[p][f];
    107             DFS(p);
    108         }
    109     }
    110 
    111     for(int i = 2; i <= tot; i++) {
    112         add(fail[i], i);
    113         //printf("add %d %d len = %d %d 
    ", fail[i], i, len[fail[i]], len[i]);
    114     }
    115     DFS_1(1);
    116 
    117     for(int i = 1; i <= n; i++) {
    118         int p = 1, t = str[i].size(), ans = 0;
    119         //printf("i = %d 
    ", i);
    120         for(int j = 0; j < t; j++) {
    121             int f = str[i][j] - 'a';
    122             p = tr[p][f];
    123             ans += cnt[p];
    124             //printf(" > p = %d ans += %d 
    ", p, cnt[p]);
    125         }
    126         printf("%d ", ans);
    127     }
    128 
    129     return 0;
    130 }
    AC代码
  • 相关阅读:
    UOJ#424. 【集训队作业2018】count
    框架的 总结(nop)------添加功能
    c# 调用分页(控制器端的)与时间的格式
    c# 通过关键字查询
    c#导入导出 插入数据到用户表(nop框)
    Nop权限的使用
    联合结果集的原则
    简单的结果集联合
    UNION ALL
    联合结果集
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10233034.html
Copyright © 2011-2022 走看看