题目分析:

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

代码:

 #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. .net core 2.1 开源项目 COMCMS dnc版本

    项目一直从dotnet core 1.1开始,升级到2.0,乃至如今2.1,以后保持继续更新. 但可能只是一个后台,前台的话,到时候看有没有好的模板. ------------无聊的分割线------ ...

  2. python第一章:简介与安装--小白博客

    Python简介 Python是一种计算机程序设计语言.是一种动态的.面向对象的脚本语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的.大型项 ...

  3. 怎么用npm发布一个包,详细教程

    我们已经实现了路由的自动化构建,但是我们可以看到,一大串代码怼在里面.当然你也可以说,把它封装在一个JS文件里面,然后使用require('./autoRoute.js')给引入进来,那也行.但是,为 ...

  4. Mike and strings CodeForces - 798B (简洁写法)

    题目链接 时间复杂度 O(n*n*|s| ) 纯暴力,通过string.substr()函数来构造每一个字符串平移后的字符串. #include <iostream> #include & ...

  5. shell正则表达

    shell正则表达 .*和.?的比较: 比如说匹配输入串A: 101000000000100 使用 1.*1 将会匹配到1010000000001,匹配方法:先匹配至输入串A的最后, 然后向前匹配,直 ...

  6. 个人博客作业-week5-敏捷开发方法读后感

    满篇英文对一个非单词狂魔来说真的是很吃力啊… 敏捷软件开发方法是一种从1990年代开始逐渐引起广发关注的一些新型软件开发方法,是一种应对快速变化的需求的一种软件开发能力,他们的具体名称.理念.过程.术 ...

  7. Linux 典型应用之WebServer 安装和配置

    Apache的基本操作 安装 yum install httpd 启动 service httpd start  在浏览器中输入以下Ip 发现无法访问 http://192.168.1.109/ 输入 ...

  8. centos 6.9:device eth0 does not seem to be present

    VMware上安装centos6.9,克隆一个新虚机,网卡不能桥接获得宿主机网络地址. https://blog.csdn.net/xiaobei4929/article/details/405152 ...

  9. windows 内建环境变量

    PS C:\Windows> ls env: Name Value ---- ----- _NT_SYMBOL_PATH srv*C:\Users\vv\Documents\symbols AL ...

  10. transform: translate(-50%, -50%) 实现块元素百分比下居中

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...