zoukankan      html  css  js  c++  java
  • bzoj 3277: 串

    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;
    }
    
    
  • 相关阅读:
    wsl 如何去掉 windows 的环境变量
    wget出现Unable to establish SSL connection
    openssh 升级
    element/JS文件上传和下载excel问题
    mysql操作过程中常见问题汇总
    [VB.NET Tips]线程传递参数四种方法
    主路由拨号_openwrt做旁路由_ipv4端口映射的设置
    Openwrt_Linux_crontab任务_顺序执行脚本
    Armbian_笔记
    Debian10_Centos8_fail2ban
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8747919.html
Copyright © 2011-2022 走看看