因为不会SAM,考虑SA。将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法。

  对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了。这是一个主席树的经典问题,对每个数找到上次出现位置扔进去即可。这样就做到O(nlog2n)了。

  可以进一步优化到O(nlogn),不是很会。

  以及我又不会写SA了,没救。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 200010
int n,m,tot,pos[N],cnt[N],end[N],sa[N],sa2[N],rk[N<<],tmp[N<<],h[N],lg2[N],f[N][],root[N],pre[N],p[N],cnt2=;
long long ans[N];
struct data{int l,r,x;
}tree[N<<];
char s[N],c[N];
void make(int n)
{
int m=;
for (int i=;i<=n;i++) cnt[rk[i]=s[i]]++,m=max(m,(int)s[i]);
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[rk[i]]--]=i;
for (int k=;k<=n;k<<=)
{
int p=;
for (int i=n-k+;i<=n;i++) sa2[++p]=i;
for (int i=;i<=n;i++) if (sa[i]>k) sa2[++p]=sa[i]-k;
memset(cnt,,sizeof(cnt));
for (int i=;i<=n;i++) cnt[rk[i]]++;
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[rk[sa2[i]]]--]=sa2[i];
memcpy(tmp,rk,sizeof(rk));
p=rk[sa[]]=;
for (int i=;i<=n;i++)
{
if (tmp[sa[i]]!=tmp[sa[i-]]||tmp[sa[i]+k]!=tmp[sa[i-]+k]) p++;
rk[sa[i]]=p;
}
m=p;if (m>=n) break;
}
for (int i=;i<=n;i++)
{
h[i]=max(h[i-]-,);
while (s[i+h[i]]==s[sa[rk[i]-]+h[i]]) h[i]++;
}
for (int i=;i<=n;i++) f[i][]=h[sa[i]];
lg2[]=;
for (int i=;i<=n;i++)
{
lg2[i]=lg2[i-];
if ((<<lg2[i])<=i) lg2[i]++;
}
for (int j=;j<=;j++)
for (int i=;i<=n;i++)
f[i][j]=min(f[i][j-],f[min(i+(<<j-),n)][j-]);
}
int query(int x,int y)
{
if (x>y) swap(x,y);
x++;if (x>y) return N;
return min(f[x][lg2[y-x+]],f[y-(<<lg2[y-x+])+][lg2[y-x+]]);
}
void ins(int &k,int l,int r,int x)
{
tree[++cnt2]=tree[k],k=cnt2;tree[k].x++;
if (l==r) return;
int mid=l+r>>;
if (x<=mid) ins(tree[k].l,l,mid,x);
else ins(tree[k].r,mid+,r,x);
}
bool Query(int x,int y,int l,int r,int p,int m)
{
if (m<=) return ;
if (!y) return ;
if (l==r) return m<=tree[y].x-tree[x].x;
int mid=l+r>>;
if (p<=mid) return Query(tree[x].l,tree[y].l,l,mid,p,m);
else return Query(tree[x].r,tree[y].r,mid+,r,p,m-tree[tree[y].l].x+tree[tree[x].l].x);
}
void build()
{
for (int i=;i<=tot;i++) pre[i]=p[pos[sa[i]]],p[pos[sa[i]]]=i;
for (int i=;i<=tot;i++)
{
root[i]=root[i-];
ins(root[i],,tot,pre[i]);
}
}
bool check(int x,int k,int m)
{
int p,q,l=,r=x;
while (l<=r)
{
int mid=l+r>>;
if (query(mid,x)>=k) p=mid,r=mid-;
else l=mid+;
}
l=x,r=tot;
while (l<=r)
{
int mid=l+r>>;
if (query(mid,x)>=k) q=mid,l=mid+;
else r=mid-;
}
return Query(root[p-],root[q],,tot,p-,m);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3277.in","r",stdin);
freopen("bzoj3277.out","w",stdout);
const char LL[]="%I64d ";
#else
const char LL[]="%lld ";
#endif
n=read(),m=read();
for (int i=;i<=n;i++)
{
scanf("%s",c+);int m=strlen(c+);
for (int j=;j<=m;j++) s[++tot]=c[j],pos[tot]=i;
s[++tot]='$',pos[tot]=i;end[i]=tot;
}
make(tot);
build();
for (int i=;i<=tot;i++)
if (s[i]!='$')
{
int l=,r=end[pos[i]]-i,x=;
while (l<=r)
{
int mid=l+r>>;
if (check(rk[i],mid,m)) x=mid,l=mid+;
else r=mid-;
}
ans[pos[i]]+=x;
}
for (int i=;i<=n;i++) printf(LL,ans[i]);
return ;
}

BZOJ3277 串(后缀数组+二分答案+主席树)的更多相关文章

  1. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  2. bzoj3277 串 (后缀数组+二分答案+ST表)

    常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...

  3. BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案

    Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...

  4. BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案

    BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单 ...

  5. BZOJ5343: [Ctsc2018]混合果汁 二分答案+主席树

    分析: 整体二分或二分答案+主席树,反正没有要求强制在线,两个都可以做... 贪心还是比较显然的,那么就是找前K大的和...和CQOI的任务查询系统很像 附上代码: #include <cstd ...

  6. BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树

    BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树 题意:给出每个果汁的价格p,美味度d,最多能放的体积l.定义果汁混合后的美味度为果汁的美味度的最小值. m次询问,要求花费不大于g, ...

  7. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  8. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  9. 2019杭电多校第四场hdu6621 K-th Closest Distance(二分答案+主席树)

    K-th Closest Distance 题目传送门 解题思路 二分答案+主席树 先建主席树,然后二分答案mid,在l和r的区间内查询[p-mid, p+mid]的范围内的数的个数,如果大于k则说明 ...

随机推荐

  1. EF6.0 code first感触

    随着EF技术的更新现在已经到了EF7.0时代,追随着技术的大潮去不断更新迭代自己,让自己知道自己还没有被技术抛弃. 今天看了下EF 6.0 codefist技术,简单,对于传统的DAL层省去了大量的人 ...

  2. 【日常训练】Help Chef Gerasim(Codeforces 99B)

    题意与分析 需要注意非法情况.换言之,合法情况其实很苛刻. 代码 /* * ACM Code => cf99b.java * Written by Sam X * Date: 三月, 19, 2 ...

  3. JUC——延迟队列

    所谓的延迟队列最大的特征是它可以自动通过队列进行脱离,例如:现在有一些对象被临时保存着,但是有可能该集合对象是一个公共对象,那么里面的某些数据如果不在使用的时候就希望其可以在指定的时间达到后自动的消失 ...

  4. Unity新版本VR以及SteamVR基础

    一.Unity2018新版本VR Unity 简单VRDemo搭建 Unity环境搭建: PlayerSetting设置如下: 启动虚拟现实驱动,sdk选择OpenVR.HTC  Vive只支持Ope ...

  5. SpringCloud 学习(二)-1 :服务注册与发现Eureka扩展

    上一篇介绍了Eureka Server的搭建跟配置.Eureka Client的搭建跟配置.服务间通过服务名调用等,还有几个实际实验中遇到的问题及处理方案,本篇来玩一下Eureka的其他配置. 上一篇 ...

  6. C++ 单例模式总结与剖析

    目录 C++ 单例模式总结与剖析 一.什么是单例 二.C++单例的实现 2.1 基础要点 2.2 C++ 实现单例的几种方式 2.3 单例的模板 三.何时应该使用或者不使用单例 反对单例的理由 参考文 ...

  7. window搭建私有云,只要几分钟

    本文介绍如何在window搭建私有云网盘. 工具/原料:一台window系统电脑或者window服务器(vps),Xampp 安装包,可道云kodexplorer安装包 第一步,xampp安装 1.官 ...

  8. 对 CasperJS 进行远程调试

    CasperJS运行在PhantomJS之上,其实也是启用PhantomJS的远程调试功能 PhantomJS 是一个无图形界面的浏览器,它支持各种Web标准:DOM处理,CSS选择器,JSON,Ca ...

  9. php 常用英语小汇

    bstract抽象的 -挨伯丝拽克特 access存取.访问 -挨克色丝 account账户 -厄靠恩特 action动作 -爱克身 activate激活 -爱克特维特 active活动的 -爱克得 ...

  10. TeamWork#3,Week5,Scrum Meeting 11.16

    到目前为止各方面工作已经基本完成,爬虫程序也调整完毕,正在等待全部整合. 成员 已完成 待完成 彭林江 完成爬虫结构调整 新爬虫与服务器连接 郝倩 完成爬虫结构调整 新爬虫与服务器连接 高雅智 重定位 ...