题目分析:

用"$"连接后缀数组,然后做一个主席树求区间内不同的数的个数。二分一个前缀长度再在主席树上求不同的数的个数。

代码:

 #include<bits/stdc++.h>
using namespace std; const int maxn = ;
const int N = ; int m,n,k;
string hmk[maxn],str;
int sum[maxn]; int sa[maxn],rk[maxn],X[maxn],Y[maxn];
int height[maxn],h[maxn],RMQ[maxn][],Tnum;
long long ans[maxn]; struct node{
int ch[],sum;
}CMT[maxn*]; int chk(int x,int k){
return rk[sa[x]]==rk[sa[x-]]&&rk[sa[x]+(<<k)]==rk[sa[x-]+(<<k)];
} void getsa(){
for(int i=;i<n;i++) X[str[i]]++;
for(int i=;i<=N;i++) X[i] += X[i-];
for(int i=n-;i>=;i--) sa[X[str[i]]--] = i;
for(int i = , num = ;i <= n;i++)
rk[sa[i]] = (str[sa[i]] == str[sa[i-]]?num:++num);
rk[sa[]] = ;
for(int k=;(<<k-)<=n;k++){
for(int i=;i<=N;i++) X[i] = ;
for(int i=n-(<<k-);i<n;i++) Y[i-n+(<<k-)+]=i;
for(int i=,j=(<<k-)+;i<=n;i++)
if(sa[i]>=(<<k-))Y[j++]=sa[i]-(<<k-);
for(int i=;i<n;i++) X[rk[i]]++;
for(int i=;i<=N;i++) X[i]+=X[i-];
for(int i=n;i>=;i--) sa[X[rk[Y[i]]]--] = Y[i];
int num = ; Y[sa[]] = ;
for(int i=;i<=n;i++) Y[sa[i]] = (chk(i,k-)?num:++num);
for(int i=;i<n;i++) rk[i] = Y[i];
if(num == n) break;
}
}
void getheight(){
for(int i=;i<n;i++){
if(i) h[i] = max(,h[i-]-); else h[i] = ;
if(rk[i] == ) continue;
int comp = sa[rk[i]-];
while(str[comp+h[i]] == str[i+h[i]])h[i]++;
}
for(int i=;i<n;i++) height[rk[i]] = h[i];
for(int i=;i<=n;i++) RMQ[i][] = height[i];
for(int k=;(<<k)<=n;k++){
for(int i=;i<=n;i++){
if(i+(<<k-)>n) RMQ[i][k]=RMQ[i][k-];
else RMQ[i][k] = min(RMQ[i][k-],RMQ[i+(<<k-)][k-]);
}
}
} int pww[maxn];
int getLCP(int L,int R){
if(L == R) return n-sa[L];
L++;
int k = pww[R-L+];
return min(RMQ[L][k],RMQ[R-(<<k)+][k]);
} void build_empty_tree(int now,int tl,int tr){
if(tl == tr) return;
int mid = (tl+tr)/;
Tnum++; CMT[now].ch[] = Tnum;
build_empty_tree(Tnum,tl,mid);
Tnum++; CMT[now].ch[] = Tnum;
build_empty_tree(Tnum,mid+,tr);
} void Modify(int lst,int now,int tl,int tr,int pos,int dt){
CMT[now] = CMT[lst];
if(tl == tr){CMT[now].sum += dt;}
else{
int mid = (tl+tr)/;
if(pos <= mid){
CMT[now].ch[] = ++Tnum;
Modify(CMT[lst].ch[],Tnum,tl,mid,pos,dt);
}else{
CMT[now].ch[] = ++Tnum;
Modify(CMT[lst].ch[],Tnum,mid+,tr,pos,dt);
}
CMT[now].sum += dt;
}
} int imp[maxn],his[maxn];
void build_CMT(){
his[] = ;
for(int i=;i<=n;i++){
if(imp[sum[sa[i]]]){
int z = ++Tnum;
Modify(his[i-],z,,n,imp[sum[sa[i]]],-);
his[i] = ++Tnum; imp[sum[sa[i]]] = i;
Modify(z,his[i],,n,i,);
}else{
his[i] = ++Tnum; imp[sum[sa[i]]] = i;
Modify(his[i-],his[i],,n,i,);
}
}
} int query(int now,int tl,int tr,int l,int r){
if(tl >= l && tr <= r) return CMT[now].sum;
if(tl > r || tr < l) return ;
int mid = (tl+tr)/;
int as=query(CMT[now].ch[],tl,mid,l,r)+query(CMT[now].ch[],mid+,tr,l,r);
return as;
} int rgt[maxn];
void work(){
getsa();
getheight();
sum[n] = ;rgt[n] = n;
for(int i=n-;i>=;i--){
sum[i] = sum[i+]+(str[i] == '$');
if(str[i] == '$') rgt[i] = i;
else rgt[i] = rgt[i+];
}
Tnum = ;
build_empty_tree(,,n);
build_CMT();
for(int i=m;i<=n;i++){
int l = ,r = rgt[sa[i]]-sa[i];
while(l < r){
int mid = (l+r+)/;
int al = ,ar = i;
while(al < ar){
int midd = (al+ar)/;
if(getLCP(midd,i) >= mid) ar = midd;
else al = midd+;
}
int tl = i,tr = n;
while(tl < tr){
int midd = (tl+tr+)/;
if(getLCP(i,midd) >= mid) tl = midd;
else tr = midd-;
}
int mmp = query(his[tl],,n,al,tl);
if(mmp >= k) l = mid;
else r = mid-;
}
ans[m-sum[sa[i]]+] += l;
}
for(int i=;i<=m;i++) printf("%lld ",ans[i]);
} int main(){
ios::sync_with_stdio(false);
cin.tie();
cin >> m >> k;
for(int i=;i<=m;i++) cin >> hmk[i];
for(int i=;i<m;i++) str += hmk[i],str += '$';
str += hmk[m];
n = str.length();
pww[] = ;
for(int i=;i<=n;i++) pww[i] = pww[i/]+;
work();
return ;
}

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

  1. BZOJ3277 串(后缀数组+二分答案+主席树)

    因为不会SAM,考虑SA.将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法. 对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了.这是 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. webpack打包经验——处理打包文件体积过大的问题

    前言 最近对一个比较老的公司项目做了一次优化,处理的主要是webpack打包文件体积过大的问题. 这里就写一下对于webpack打包优化的一些经验. 主要分为以下几个方面: 去掉开发环境下的配置 Ex ...

  2. 【中文版 | 论文原文】BERT:语言理解的深度双向变换器预训练

    BERT:Pre-training of Deep Bidirectional Transformers for Language Understanding 谷歌AI语言组论文<BERT:语言 ...

  3. 【深度学习】一文读懂机器学习常用损失函数(Loss Function)

    最近太忙已经好久没有写博客了,今天整理分享一篇关于损失函数的文章吧,以前对损失函数的理解不够深入,没有真正理解每个损失函数的特点以及应用范围,如果文中有任何错误,请各位朋友指教,谢谢~ 损失函数(lo ...

  4. Highchartsjs使用总结及实时动态刷新图

    柱状图: $('#container').highcharts({ //突显红色柱: series: [ 523, 345, 785, 565, 843,{'color': 'red','y': 30 ...

  5. 软件工程练习:模块化,单元测试,回归测试,TDD

    这是<构建之法>实战教学的一部分.适合作为同学们的第二个程序作业. 第一个程序作业: 请看 “概论” 一章的练习,或者老师的题目,例如这个. 作业要求: 软件工程的作业越来越有意思了, 我 ...

  6. spring security运行流程图(转)

    原文:http://blog.csdn.net/u011511684/article/details/31394493 示例下载地址:http://download.csdn.net/detail/u ...

  7. Servlet 快速概览

    目录 生命周期 web.xml 获取表单数据(设置请求的编码格式) 返回响应内容(设置响应的编码格式) 结合前两点,总结基本模板 获取请求协议头部信息 设置响应头部信息 使用过滤器 在web.xml中 ...

  8. API接口TOKEN设计

    首先需要知道API是什么?   API(Application Programming Interface)即应用程序接口.你可以认为 API 是一个软件组件或是一个 Web 服务与外界进行的交互的接 ...

  9. 基于redis实现的点赞功能设计思路详解

    点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysq ...

  10. Nginx三部曲(3)SSL

    我们将告诉你 Nginx 的运作模式.蕴含的概念,怎样通过调优 Nginx 来提高应用性能,或是如何设置它的启动和运行. 这个教程有三个部分: 基本概念 —— 这部分需要去了解 Nginx 的一些指令 ...