码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3277: 串

时间:2018-04-13 13:26:01      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:inline   size   包括   暴力   ++   desc   wap   条件   mem   

Description

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

Solution

出现 \(k\) 次的问题比较好解决,我们构出 \(parent\) 树,然后在上面转移就可以了
但是在一个串出现多次只算一次,所以我们用 \(set\) 转移,自动去重
然后就是统计每一个串的每一个子串了
我们要在后缀自动机上遍历出所有 \(S\) 的子串
那么我们遍历每一个后缀节点,如果没有限制的话,对于所有遍历到的节点 \(x\),答案就是 \(\sum_{x} len[x]\)
对于限制,如果不满足 \(size[x]>=k\) ,我们暴力跳父亲节点,直到满足条件位置,然后继续做就行了
也可以不这么做:
我们把满足 \(size[x]>=k\) 的节点赋值为 \(len[x]-len[fa[x]]\),不满足的赋为 \(0\),然后把父亲的权值累加,直接访问每一个串的每一个位置所代表的节点,再累加起来就行了

关于 \(set\) 合并的复杂度问题:仿佛是个wei的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
int n,K,ch[N][26],fa[N];string s[N];
int cur,cnt=1,len[N],sz[N];set<int>S[N];set<int>::iterator it;
int head[N],nxt[N*2],to[N*2],num=0;
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void dfs(int x){
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        dfs(u);
        for(it=S[u].begin();it!=S[u].end();++it)S[x].insert(*it);
        set<int>().swap(S[u]);
    }
    sz[x]=S[x].size();
}
inline void ins(int c,int id){
    int p=cur;cur=++cnt;len[cur]=len[p]+1;
    for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
    if(!p)fa[cur]=1;
    else{
        int q=ch[p][c];
        if(len[p]+1==len[q])fa[cur]=q;
        else{
            int nt=++cnt;len[nt]=len[p]+1;
            memcpy(ch[nt],ch[q],sizeof(ch[q]));
            fa[nt]=fa[q];fa[q]=fa[cur]=nt;
            for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
        }
    }
    S[cur].insert(id);
}
inline ll solve(int x){
    ll ret=0;
    for(int p=1,i=0,le=s[x].size();i<le;i++){
        int c=s[x][i]-'a';
        p=ch[p][c];
        while(p>1 && sz[p]<K)p=fa[p];
        ret+=len[p];
    }
    return ret;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d%d",&n,&K);
  for(int i=1;i<=n;i++){
      cin>>s[i];
      cur=1;
      for(int j=0,le=s[i].size();j<le;j++)ins(s[i][j]-'a',i);
  }
  for(int i=2;i<=cnt;i++)link(fa[i],i);
  dfs(1);
  for(int i=1;i<=n;i++)printf("%lld ",solve(i));
  return 0;
}

bzoj 3277: 串

标签:inline   size   包括   暴力   ++   desc   wap   条件   mem   

原文地址:https://www.cnblogs.com/Yuzao/p/8747919.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!