题目分析:

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

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3
  4 const int maxn = 132000;
  5 const int N = 130000;
  6
  7 int m,n,k;
  8 string hmk[maxn],str;
  9 int sum[maxn];
 10
 11 int sa[maxn],rk[maxn],X[maxn],Y[maxn];
 12 int height[maxn],h[maxn],RMQ[maxn][20],Tnum;
 13 long long ans[maxn];
 14
 15 struct node{
 16     int ch[2],sum;
 17 }CMT[maxn*35];
 18
 19 int chk(int x,int k){
 20     return rk[sa[x]]==rk[sa[x-1]]&&rk[sa[x]+(1<<k)]==rk[sa[x-1]+(1<<k)];
 21 }
 22
 23 void getsa(){
 24     for(int i=0;i<n;i++) X[str[i]]++;
 25     for(int i=1;i<=N;i++) X[i] += X[i-1];
 26     for(int i=n-1;i>=0;i--) sa[X[str[i]]--] = i;
 27     for(int i = 2, num = 1;i <= n;i++)
 28     rk[sa[i]] = (str[sa[i]] == str[sa[i-1]]?num:++num);
 29     rk[sa[1]] = 1;
 30     for(int k=1;(1<<k-1)<=n;k++){
 31     for(int i=1;i<=N;i++) X[i] = 0;
 32     for(int i=n-(1<<k-1);i<n;i++) Y[i-n+(1<<k-1)+1]=i;
 33     for(int i=1,j=(1<<k-1)+1;i<=n;i++)
 34         if(sa[i]>=(1<<k-1))Y[j++]=sa[i]-(1<<k-1);
 35     for(int i=0;i<n;i++) X[rk[i]]++;
 36     for(int i=1;i<=N;i++) X[i]+=X[i-1];
 37     for(int i=n;i>=1;i--) sa[X[rk[Y[i]]]--] = Y[i];
 38     int num = 1; Y[sa[1]] = 1;
 39     for(int i=2;i<=n;i++) Y[sa[i]] = (chk(i,k-1)?num:++num);
 40     for(int i=0;i<n;i++) rk[i] = Y[i];
 41     if(num == n) break;
 42     }
 43 }
 44 void getheight(){
 45     for(int i=0;i<n;i++){
 46     if(i) h[i] = max(0,h[i-1]-1); else h[i] = 0;
 47     if(rk[i] == 1) continue;
 48     int comp = sa[rk[i]-1];
 49     while(str[comp+h[i]] == str[i+h[i]])h[i]++;
 50     }
 51     for(int i=0;i<n;i++) height[rk[i]] = h[i];
 52     for(int i=1;i<=n;i++) RMQ[i][0] = height[i];
 53     for(int k=1;(1<<k)<=n;k++){
 54     for(int i=1;i<=n;i++){
 55         if(i+(1<<k-1)>n) RMQ[i][k]=RMQ[i][k-1];
 56         else RMQ[i][k] = min(RMQ[i][k-1],RMQ[i+(1<<k-1)][k-1]);
 57     }
 58     }
 59 }
 60
 61 int pww[maxn];
 62 int getLCP(int L,int R){
 63     if(L == R) return n-sa[L];
 64     L++;
 65     int k = pww[R-L+1];
 66     return min(RMQ[L][k],RMQ[R-(1<<k)+1][k]);
 67 }
 68
 69 void build_empty_tree(int now,int tl,int tr){
 70     if(tl == tr) return;
 71     int mid = (tl+tr)/2;
 72     Tnum++; CMT[now].ch[0] = Tnum;
 73     build_empty_tree(Tnum,tl,mid);
 74     Tnum++; CMT[now].ch[1] = Tnum;
 75     build_empty_tree(Tnum,mid+1,tr);
 76 }
 77
 78 void Modify(int lst,int now,int tl,int tr,int pos,int dt){
 79     CMT[now] = CMT[lst];
 80     if(tl == tr){CMT[now].sum += dt;}
 81     else{
 82     int mid = (tl+tr)/2;
 83     if(pos <= mid){
 84         CMT[now].ch[0] = ++Tnum;
 85         Modify(CMT[lst].ch[0],Tnum,tl,mid,pos,dt);
 86     }else{
 87         CMT[now].ch[1] = ++Tnum;
 88         Modify(CMT[lst].ch[1],Tnum,mid+1,tr,pos,dt);
 89     }
 90     CMT[now].sum += dt;
 91     }
 92 }
 93
 94 int imp[maxn],his[maxn];
 95 void build_CMT(){
 96     his[0] = 1;
 97     for(int i=1;i<=n;i++){
 98     if(imp[sum[sa[i]]]){
 99         int z = ++Tnum;
100         Modify(his[i-1],z,1,n,imp[sum[sa[i]]],-1);
101         his[i] = ++Tnum; imp[sum[sa[i]]] = i;
102         Modify(z,his[i],1,n,i,1);
103     }else{
104         his[i] = ++Tnum; imp[sum[sa[i]]] = i;
105         Modify(his[i-1],his[i],1,n,i,1);
106     }
107     }
108 }
109
110 int query(int now,int tl,int tr,int l,int r){
111     if(tl >= l && tr <= r) return CMT[now].sum;
112     if(tl > r || tr < l) return 0;
113     int mid = (tl+tr)/2;
114     int as=query(CMT[now].ch[0],tl,mid,l,r)+query(CMT[now].ch[1],mid+1,tr,l,r);
115     return as;
116 }
117
118 int rgt[maxn];
119 void work(){
120     getsa();
121     getheight();
122     sum[n] = 1;rgt[n] = n;
123     for(int i=n-1;i>=0;i--){
124     sum[i] = sum[i+1]+(str[i] == '$');
125     if(str[i] == '$') rgt[i] = i;
126     else rgt[i] = rgt[i+1];
127     }
128     Tnum = 1;
129     build_empty_tree(1,1,n);
130     build_CMT();
131     for(int i=m;i<=n;i++){
132     int l = 0,r = rgt[sa[i]]-sa[i];
133     while(l < r){
134         int mid = (l+r+1)/2;
135         int al = 1,ar = i;
136         while(al < ar){
137         int midd = (al+ar)/2;
138         if(getLCP(midd,i) >= mid) ar = midd;
139         else al = midd+1;
140         }
141         int tl  = i,tr = n;
142         while(tl < tr){
143         int midd = (tl+tr+1)/2;
144         if(getLCP(i,midd) >= mid) tl = midd;
145         else tr = midd-1;
146         }
147         int mmp = query(his[tl],1,n,al,tl);
148         if(mmp >= k) l = mid;
149         else r = mid-1;
150     }
151     ans[m-sum[sa[i]]+1] += l;
152     }
153     for(int i=1;i<=m;i++) printf("%lld ",ans[i]);
154 }
155
156 int main(){
157     ios::sync_with_stdio(false);
158     cin.tie(0);
159     cin >> m >> k;
160     for(int i=1;i<=m;i++) cin >> hmk[i];
161     for(int i=1;i<m;i++) str += hmk[i],str += '$';
162     str += hmk[m];
163     n = str.length();
164     pww[1] = 0;
165     for(int i=2;i<=n;i++) pww[i] = pww[i/2]+1;
166     work();
167     return 0;
168 }

转载于:https://www.cnblogs.com/Menhera/p/10102070.html

BZOJ3277 串 【后缀数组】【二分答案】【主席树】相关推荐

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

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

  2. [BZOJ4310]跳蚤-后缀数组-二分答案

    跳蚤 Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择 ...

  3. SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)

    [题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...

  4. BZOJ3998 TJOI2015弦论(后缀数组+二分答案)

    先看t=1的情况.显然得求出SA(因为我不会SAM).我们一位位地确定答案.设填到了第len位,二分这一位填什么之后,在已经确定的答案所在的范围(SA上的某段区间)内二分,找到最后一个小于当前串的后缀 ...

  5. codefores 204E. Little Elephant and Strings(后缀数组,RMQ求lcp,二分,主席树)

    题目链接 E. Little Elephant and Strings time limit per test3 seconds memory limit per test256 megabytes ...

  6. [2020.11.26NOIP模拟赛]勇者的后缀【SA,RMQ,主席树,二分】

    正题 题目链接:https://www.luogu.com.cn/problem/U142356?contestId=37784 题目大意 一个字符串,询问给出(x,l,r)(x,l,r)(x,l,r ...

  7. L3-002 堆栈 树状数组+二分答案

    题目详情点击这里 思路:用std::stack来表示题目中说的栈,现在关键问题就是如何找到中位数. 可以用二分答案+树状数组的方法 由于每个元素最大不超过1e5,因此开一个大小为1e5的树状数组来存储 ...

  8. 洛谷 P4094 [HEOI2016/TJOI2016]字符串 后缀数组+二分+主席树

    题目链接 后缀数组 题目分析: sa[i] – 第i小的后缀的编号 rank[i] --编号为i的后缀排第几: height[i] – 第i和第i-1的最长lcp最长公共前缀: 1.二分答案,答案肯定 ...

  9. 洛谷 P2468 粟粟的书架 二分(主席树+前缀和)

    传送~:https://www.luogu.org/problem/P2468 看了一下数据也发现是两道题,后边当他是一个序列(n==1)的时候直接主席树二分区间前k大和就行了 但是有一个细节我觉得就 ...

  10. HDU - 5030 Rabbit's String(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,现在要求将其分为不大于k个连续的子串,对于每个子串求出字典序最大的子串,现在要求所有子串的最大子串的最大值最小,输出这个最大子串 题目分析:最大值最小,标 ...

最新文章

  1. 读农民工兄弟学C#文章后的感觉
  2. CTFshow 反序列化 web267
  3. 梯度下降法原理及实现
  4. SemSorGrid4Env
  5. 10月16日培训日记
  6. 数学--数论--快速幂--最大公约数--位运算模板
  7. 容器编排技术 -- Init 容器
  8. 【转载】用平常语言介绍神经网络
  9. 工程数学(数值分析)第三讲:求解线性代数方程组
  10. 牛客网暑期ACM多校训练营(第五场): F. take(期望+线段树)
  11. 如何在Linux中使用netstat命令
  12. Angular4记账webApp练手项目之四(在Angular4项目中用echarts绘制图表)
  13. 史上最全的黑苹果系统「MacOS」安装教程,小白也能秒掌握!
  14. linux虚拟实验室关闭了,Linux在线虚拟云实验室,提升RHCE考试通过率
  15. Win7系统如何安装声卡驱动
  16. ss和netstat的区别
  17. DSP你都不知道是啥,还好意思说自己学过嵌入式?
  18. 主元分析法 matlab,数值分析实习作业之不选主元法高斯分解(Matlab)
  19. C#获取目录下所有文件的列表——最白话,手把手教你做系列。
  20. 计算机网络分代核心的属性,计算机网络开发专业核心能力题库-操作

热门文章

  1. three.js 入门详解(一)
  2. 洛谷P1179 [NOIP2010 普及组] 数字统计题解
  3. 石乙己——孔乙己程序员版
  4. 左斜杠和右斜杠的区别
  5. matlab将txt转成dat,将matlab中数据保存为txt或dat格式
  6. [精简]托福核心词汇23
  7. 计算机win7如何连接wifi网络,细说win7怎么共享wifi
  8. 动画插件--WOWJS
  9. div 背景色设置_DIV背景颜色设置
  10. 【冬瓜哥雄文】高端存储系统江湖风云录!