3473: 字符串

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 121  Solved: 53
[Submit][Status][Discuss]

Description

给定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% 的数据,1<=n,k<=10^5,所有字符串总长不超过10^5,字符串只包含小写字母。

Source

Adera 1 杯冬令营模拟赛

很久之前做的题今天一看竟然不会做了。。。于是补篇题解。

首先把所有串连起来做一遍SA,求出hight,然后在后缀数组上从前往后扫。

那么现在要求的就是当前这个后缀有多少前缀是至少k个串的子串,这些前缀一定是连续的一段,因为如果Sx出现了k次,那么S也一定出现了k次。

设当前位是i,我们现在拥有后缀数组上一位的答案lastans,那么把它与hight[i]取一个min得到x,那么这位的答案至少是x。

然后考虑这位新出现的子串,那些包含这些子串的位置一定在i下面,那么维护一个指针使当前区间内刚好包含k个不同串的任意一个后缀,当i++时指针往后扫。

那么指针的位置与i用ST表求个区间RMQ,用x与这个区间最小值取max就是当前位的答案。

复杂度$nlogn$

感觉后缀自动机的做法很不科学

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define ll long long
using namespace std;
int n,k;
int sa[N],rank[N],wb[N],sum[N],c[N];
void getsa(int n,int m)
{
int *x=rank,*y=wb;
for(int i=0;i<m;i++)sum[i]=0;
for(int i=0;i<n;i++)sum[x[i]=c[i]]++;
for(int i=1;i<m;i++)sum[i]+=sum[i-1];
for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;
int p=1;
for(int j=1;p<n;j<<=1,m=p)
{
p=0;
for(int i=n-j;i<n;i++)y[p++]=i;
for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(int i=0;i<m;i++)sum[i]=0;
for(int i=0;i<n;i++)sum[x[i]]++;
for(int i=1;i<m;i++)sum[i]+=sum[i-1];
for(int i=n-1;i>=0;i--)sa[--sum[x[y[i]]]]=y[i];
swap(x,y);x[sa[0]]=0;p=1;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
}
}
int h[N];
void calh(int n)
{
for(int i=1;i<=n;i++)rank[sa[i]]=i;
int kk=0;
for(int i=0;i<n;i++)
{
if(kk)kk--;
int j=sa[rank[i]-1];
while(c[i+kk]==c[j+kk])kk++;
h[rank[i]]=kk;
}
return ;
}
int mn[N][20],lg[N];
void ST()
{
lg[0]=-1;
for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++)mn[i][0]=h[i];
for(int i=1;i<=19;i++)
{
for(int j=1;j<=n;j++)
{
if(j+(1<<(i-1))<=n)mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
else mn[j][i]=mn[j][i-1];
}
}return ;
}
int qur(int l,int r)
{
int k=lg[r-l+1];
return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
int be[N];
ll ans[N];
int len[N],sz[N];
int now[N],nw;
void solve()
{
int l=0;int tmp=0;
for(int i=1;i<=n;i++)
{
if(i!=1&&be[sa[i-1]]!=0)
{
now[be[sa[i-1]]]--;
if(!now[be[sa[i-1]]])nw--;
}
while(l!=n&&nw<k)
{
l++;
if(be[sa[l]]!=0)
{
now[be[sa[l]]]++;
if(now[be[sa[l]]]==1)nw++;
}
}
tmp=min(tmp,h[i]);
if(nw==k)
{
if(be[sa[i]])
{
int num;
if(l!=i)num=qur(i+1,l);
else num=sz[sa[i]];
tmp=max(tmp,num);
}
}
ans[be[sa[i]]]+=tmp;
}
return ;
}
char s[N];
int main()
{
int cnt;
scanf("%d%d",&cnt,&k);
int m=256;n=-1;
for(int i=1;i<=cnt;i++)
{
scanf("%s",s+1);len[i]=strlen(s+1);
for(int j=1;j<=len[i];j++)
{
c[++n]=s[j];
be[n]=i;
sz[n]=len[i]-j+1;
}
if(i!=cnt)c[++n]=m++;
}n++;
getsa(n+1,m);calh(n);
ST();
solve();
for(int i=1;i<cnt;i++)printf("%lld ",ans[i]);
printf("%lld",ans[cnt]);
return 0;
}

  

  

bzoj3473: 字符串 && bzoj3277串的更多相关文章

  1. bzoj3473字符串&bzoj3277串

    题意:给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串.注意本质相同的子串多次出现算多次,如1 1 aaa这组数据答案为6,贡献1WA.代码里有些部分是为了 ...

  2. BZOJ3473&&BZOJ3277串

    BZOJ3473&&BZOJ3277串 题面 自己找去 HINT 对于所有串建立一个广义后缀自动机,对于每一个节点开一个set表示这个节点接受的子串在哪些串里出现过,然后在parent ...

  3. 汇编语言从键盘输入一个字符串(串长不大于80)以十进制输出字符串中非字母字符的个数(不是a to z或 A to Z)

    (1)从键盘输入一个字符串(串长不大于80). (2)以十进制输出字符串中非字母字符的个数(不是a to z或 A to Z). (3)输出原字符串且令非字母字符闪烁显示. (4)找出字符串中ASCI ...

  4. BZOJ3277 串 和 BZOJ3473 字符串

    字符串 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? 分析 参照自为风月马前卒和Candy?的题解. 广义后缀自动机不就是把很多串的SAM建到了一个S ...

  5. BZOJ3277——串

    0.题意:给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 1.分析:这个题我问了吴大爷做法 首先建立后缀自动机,然后利用离线搞出每一个 ...

  6. PHP 中替换若干字符串字串为数组中的值,不用循环,非常高效

    替换某个字符串中的一个或若干个字串为数组中某些值 php本身有自带的函数,可以不用循环非常高效的实现其效果: 实例代码:   $phrase  = "You should eat fruit ...

  7. BZOJ3473: 字符串

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 109  Solved: 47[Submit][Status] Descriptio ...

  8. SAP ABAP 处理字符串串串串串串串串(详细)

    关于ABAP中处理字符串的方法,非常详细,学习过程中总结一下分享给大家,,, ABAP/4 提供多个处理类型 C 即字符串 的数据对象的关键字. 处理字符串 的方法有: 1.拆分字符串split 2. ...

  9. BZOJ3473: 字符串【后缀数组+思维】

    Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...

随机推荐

  1. netcore如何引用package?

    netcore项目引用dll包,分如下三种: 1.引用网络包 从nuget获取,然后引入,使用命令:dotnet add package 包名 然后:dotnet restore 2.引用同解决方案的 ...

  2. AJAX请求中出现OPTIONS请求

    背景 有一个前后端分离的VUE项目来发送ajax请求, 查看Nginx日志或使用Chrome Dev Tools查看请求发送情况时, 会看到每次调后台API的请求之前, 都会发送一个OPTIONS请求 ...

  3. ossec安装

    安装 安装要求 对于Unix系统来说,OSSEC只需要GNU的make.gcc和libc.推荐使用OpenSSL,但仅属于一个可选项.而且,通常您只需在一个系统上做编译操作,然后将二进制程序复制到其他 ...

  4. OSSEC 架构

    OSSEC由很多部分组成,它有一个集中的管理端,用于监控.并接收来自代理.syslog.数据库或无代理设备的日志. 管理端(服务器) 管理端属于OSSEC部署中的中心部分.它存储了文件完整性检测数据库 ...

  5. oracle安装出错/runInstaller

    http://blog.csdn.net/yabingshi_tech/article/details/48313955 http://www.cnblogs.com/lihaozy/archive/ ...

  6. 如何将office卸载干净

    我试了控制面板卸载office软件等方法,发现一直卸载不干净. 后发现这个office的官方链接,根据这个链接的步骤就很轻松的卸载好了. https://support.office.com/zh-c ...

  7. 渡过OO的死劫,了解规格的意义——OO第三次博客总结

    当熬过了一次次黑暗,迎接我们的却是被扣的惨不忍睹的JSF ┭┮﹏┭┮ 一.总结调研 规格的历史 传统科学的特点是发现世界,而软件的特点是构造世界.软件的最底层就是0,1,两个离散的值.程序设计语言的三 ...

  8. 灵悟礼品网上专卖店——画出E-R图

    一.小组成员: 洪雪意(产品负责人) 陈淑筠(Master) 二.组内人员任务情况 计划完成的任务的第三个模块:分析并建立数据库 已完成的任务: 任务的第三个模块: 陈淑筠(完成任务1):画出商品资料 ...

  9. 阅读 DPDK 中文论文两则

    基于DPDK的高效数据包捕获技术分析与应用 本文应用场景 网络安全领域的数据包捕获技术,对系统有高性能需求,要在短时间内成功收集.分析.处理大量数据,实时捕获效率低下. 旧有传统数据包处理机制 BPF ...

  10. Software Defined Networking(Week 2, part 1)

    History of SDN 1.1 - 1.2 本节讨论从上世纪八十年代时到现在为止出现的SDN的思想和发展历史.了解历史,可以明白技术后面的成因以及一些原则,并从架构上去大致掌握.了解一些主旨. ...