• bzoj 3277: 串


    以下全部是笔记,不要看了

    注意:要求的不是"有多少不同的子串是...",相同的要重复计算贡献。

    例如:

    3 2
    aca
    a
    c
    答案是3 1 1

    第一个串中两个a都出现了两次,c出现了两次,所以第一个的答案是3

    广义后缀自动机模板。

    各个串连起来中间加分隔符的不方便,一般都要加很多特判的。。。。

    有的说不定就不能用了。。

    可以直接对着多个串建。就一句话:

    把很多串的SAM建到了一个SAM上,建每个串的时候都从root开始(last=root)

    https://www.cnblogs.com/candy99/p/6374177.html

    http://dwjshift.logdown.com/posts/304570

    (也可以在trie上建,大概就是每个节点建时last就是父亲建完的np?没试过)

    这样子复杂度可以证明是O(G(T))(好像要乘上字符集大小?没确定),G(T)为Trie树上所有叶子节点深度和,一定不超过所有串长度和

    这样子插入的时候要判断是否已经存在对应节点,如果存在则考虑直接复用或者拆开后复用(就是普通的后缀自动机构建头上加一点跟后面很像的东西)

    建出后缀树后,对于每一个节点维护一个集合,表示这个点到根的路径表示的后缀属于哪些字符串

    对于每个节点计算贡献(一开始不直接将答案更新到对应字符串上,只更新到节点上,曾经陷入误区),就是如果它到根表示的后缀出现超过一次(就是以它为根的子树中各个集合的并集的size>1),那么产生len[t]-len[par[t]]的贡献,否则不产生贡献

    最后还要一遍dfs把各个节点的答案加到以其为根子树中各个节点的答案上(将每个后缀的实际贡献更新为其各个前缀的贡献之和,达到求一个字符串所有子串贡献的目的)

    这个地方我用了启发式合并来统计不同子串数量,好像有转换到序列上用树状数组做的方法。。。

    最后每个串的答案就是其每个位置对应的后缀的答案之和

    上面基本全是假的看不懂的。。。。还是意识流吧

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<queue>
      5 #include<vector>
      6 #include<set>
      7 using namespace std;
      8 int n,x;
      9 char ss[100100],*sp=ss,*pp[100100];
     10 int le[100100];
     11 vector<int> tt[100100];
     12 namespace SAM
     13 {
     14     int mem,root;
     15     int len[300100],par[300100];
     16     int trans[300100][26];
     17     void append(int ch,int& np)
     18     {
     19         int p=np;
     20         //如果已经存在倒着的原串首部加上ch的串
     21         if(trans[p][ch])
     22         {
     23             int q=trans[p][ch];
     24             if(len[q]==len[p]+1)//如果没有被压过
     25                 np=trans[np][ch];
     26             else//如果被压了,要拆开
     27             {
     28                 np=++mem;len[np]=len[p]+1;
     29                 par[np]=par[q];par[q]=np;
     30                 memcpy(trans[np],trans[q],sizeof(trans[np]));
     31                 for(;p&&trans[p][ch]==q;p=par[p])    trans[p][ch]=np;
     32             }
     33             return;
     34         }
     35         np=++mem;len[np]=len[p]+1;
     36         for(;p&&!trans[p][ch];p=par[p])    trans[p][ch]=np;
     37         if(!p)    par[np]=root;
     38         else
     39         {
     40             int q=trans[p][ch];
     41             if(len[q]==len[p]+1)    par[np]=q;
     42             else
     43             {
     44                 int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
     45                 memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1;
     46                 for(;p&&trans[p][ch]==q;p=par[p])    trans[p][ch]=nq;
     47             }
     48         }
     49     }
     50     set<int> ss[301000];
     51     int in[300100];
     52     long long ans[300100];
     53     queue<int> q;
     54     vector<int> son[300100];
     55     void dfs(int u)
     56     {
     57         for(int i=0;i<son[u].size();i++)
     58         {
     59             ans[son[u][i]]+=ans[u];
     60             dfs(son[u][i]);
     61         }
     62     }
     63     void work()
     64     {
     65         int i,t;
     66         for(i=1;i<=mem;i++)    in[par[i]]++;
     67         for(i=1;i<=mem;i++)
     68             if(!in[i])
     69                 q.push(i);
     70         set<int>::iterator it;
     71         while(!q.empty())
     72         {
     73             t=q.front();q.pop();
     74             if(!t)    continue;
     75             if(ss[t].size()>=x)    ans[t]=(len[t]-len[par[t]]);
     76             if(ss[par[t]].size()<ss[t].size())    swap(ss[par[t]],ss[t]);
     77             for(it=ss[t].begin();it!=ss[t].end();++it)
     78                 ss[par[t]].insert(*it);
     79             in[par[t]]--;
     80             if(in[par[t]]==0)    q.push(par[t]);
     81         }
     82         for(i=1;i<=mem;i++)    son[par[i]].push_back(i);
     83         dfs(root);
     84     }
     85 }
     86 long long anss;
     87 
     88 int main()
     89 {
     90     int i,j,np;char *b,*ed;
     91     scanf("%d%d",&n,&x);
     92     SAM::root=++SAM::mem;
     93     for(i=1;i<=n;i++)
     94     {
     95         scanf("%s",sp);
     96         pp[i]=sp;le[i]=strlen(sp);sp+=le[i];
     97         np=SAM::root;b=pp[i];ed=pp[i]+le[i];
     98         for(;b!=ed;b++)
     99         {
    100             SAM::append(*b-'a',np);
    101             SAM::ss[np].insert(i);
    102             tt[i].push_back(np);
    103         }
    104     }
    105     SAM::work();
    106     for(i=1;i<=n;i++)
    107     {
    108         anss=0;
    109         for(j=0;j<tt[i].size();j++)    anss+=SAM::ans[tt[i][j]];
    110         printf("%lld ",anss);
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    ztree
    SAMEORIGIN
    Unity shader学习之折射
    Unity shader学习之反射
    Unity shader学习之标准的Unity shader
    Unity shader学习之Alpha Test的阴影
    Unity shader学习之阴影,衰减统一处理
    Unity shader学习之阴影
    Unity shader学习之Forward Rendering Path
    AsyncClientUtils
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8727261.html
Copyright © 2020-2023  润新知