hdu 6194 string string string
来源:互联网 发布:美少女战士 知乎 编辑:程序博客网 时间:2024/06/05 15:21
转载自http://blog.csdn.net/My_stage/article/details/77936442
一定要看懂了再转!!!
题意: 给一个字符串,和一个k,问你串中出现k次的子串有多少个。
哎,我这次要背大大的锅,从多校开始好多字符串SA的题都在wa,wa,wa,昨天沈阳网选的也是一直处于懵逼状态。还是做题不够多,做题时想的不够啊。 dalao们都说sam(后缀自动机)也可以过,我还是回去补补自动机吧,之后再补一篇博客。
思路:
构建后缀数组后,我们已经把所有后缀全部处理出来了,之后我们对于k>1的情况,我们知道height数组代表着2个排名i,i-1后缀的公共前缀也就是lcp,那么我们按照K长度的区间查找,我们每次查找区间最小值,这个值就是这段区间内可能的结果,之后我们要看一下这段区间i~i+k-1,左边的height以及右边的height的最大值,因为如果存在值那么就说明多加了一部分所以要剪掉,之后如果出现了负值,那么就是为0的情况,之后我们慢慢遍历一遍即可。
对于k=1的情况,我们需要对于字符串总长度len,len-sa[i]代表 sa[i]为排名为i的后缀的起始位置,那么这一段就是可能出现的次数,之后我们减去两边(左边,右边的最大值即可),之后还是与0比较
#include <bits/stdc++.h> #define maxs 2020202 #define mme(i,j) memset(i,j,sizeof(i)) #define ll long long using namespace std; char s[maxs]; int c[maxs],wa[maxs]; int wb[maxs],sa[maxs],height[maxs],ranks[maxs]; void Getsa(int m,int n) { int *x=wa,*y=wb,p=0; for(int i=0; i<m; i++) c[i]=0; for(int i=0; i<n; i++) c[x[i]=s[i]]++; for(int i=1; i<m; i++) c[i]+=c[i-1]; for(int i=n-1; i>=0; i--) sa[--c[x[i]]]=i; for(int k=1; p<n; k<<=1,m=p) { p=0; for(int i=n-k; i<n; i++) y[p++]=i; for(int i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0; i<m; i++) c[i]=0; for(int i=0; i<n; i++) c[x[y[i]]]++; for(int i=1; i<m; i++) c[i]+=c[i-1]; for(int i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); x[sa[0]]=0,p=1; for(int i=1; i<n; i++) if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=p-1; else x[sa[i]]=p++; } } void gethei() { int k=0,len=strlen(s); for(int i=1; i<=len; i++) ranks[sa[i]]=i; for(int i=0; i<len; i++) { if(k) k--; int j=sa[ranks[i]-1]; while(s[j+k]==s[i+k])k++; height[ranks[i]]=k; } } void text(int n) { printf("This is SA\n"); for(int i=0; i<n; i++) printf("SA[%d] is %d\n",i,sa[i]); printf("\nThis is Height\n"); for(int i=0; i<=n; i++) printf("h[%d] is %d\n",i,height[i]); } int sum[maxs<<2]; void build(int rt,int l,int r) { if(l == r) { sum[rt]=height[l]; return; } int mid =(l+r)>>1; build(rt<<1|1,mid+1,r); build(rt<<1,l,mid); sum[rt]=min(sum[rt<<1],sum[rt<<1|1]); } int ask(int al,int ar,int l,int r,int rt) { if(al<=l&&ar>=r) return sum[rt]; int mid=(l+r)>>1; int ans=1e9; if(mid>=al) ans=ask(al,ar,l,mid,rt<<1); if(mid<ar) ans=min(ans,ask(al,ar,mid+1,r,rt<<1|1)); return ans; } int main() { int t,k; scanf("%d",&t); while(t--) { scanf("%d",&k); scanf("%s",s); int len=strlen(s); Getsa(200,len+1); gethei(); build(1,1,len); height[len+1]=0; // text(len); if(k>len) { puts("0"); continue; } int ans=0; if(k==1){ for(int i=1;i<=len-k+1;i++){ ans+=max(len-sa[i]-max(height[i],height[i+k]),0); } printf("%d\n",ans); continue; } for(int i=1;i<=len-k+1;i++){ ans+=max(ask(i+1,i+k-1,1,len,1)-max(height[i],height[i+k]),0); } printf("%d\n",ans); } return 0; }
阅读全文
0 0
- HDU 6194 string string string
- HDU 6194 string string string
- HDU 6194 string string string
- HDU 6194 string string string
- HDU 6194string string string
- hdu 6194 string string string
- hdu 6194 string string string
- HDU 6194 string string string
- string string string HDU
- HDU 6194 string string string [后缀数组]
- HDU 6194 string string string【后缀数组】
- HDU 6194 string string string (SAM)
- String HDU
- string string string hdu 6194 (后缀数组做法)
- HDU 6194 string string string 后缀数组+lcp、Two Pointers
- HDU 6194 string string string 后缀数组+rmq
- hdu 6194 string string string 后缀数组+rmq+容斥
- string
- 如何去掉tomcat启动时的项目名
- 架构腐化之谜
- Mouse wheel events, event filters, and QScrollArea
- Java 虚拟机内存分配机制
- 继承AppCompatActivity的Activity无法隐藏标题栏
- hdu 6194 string string string
- Android逆向系列之动态调试7–IDA调试so文件(上)
- Apache Ignite——新一代数据库缓存系统
- tcp
- SpringMVC中controller返回json数据的两种方法
- C#中使用 StackExchange.Redis 封装属于自己的 RedisHelper
- Android之back键拦截处理
- Redis数据结构(二)
- Springmvc + Redis 整合