hdu 6194 string string string(后缀数组)

题目链接:hdu 6194 string string string

题意:

给你一个字符串,给你一个k,问你有多少个子串恰好在原串中出现k次。

题解:

后缀数组求出sa后,用height数组的信息去找答案。

每次用k长度的区间去卡height数组,求出该区间的lcp。

该区间的贡献就是ans=lcp-max(height[i],height[i+k])。

如果ans<=0,就不贡献。

比如 2 aaa

后缀数组为:

1 a

2 aa

3 aaa

height为 0,1,2

现在扫到[1,2],lcp=1,max(height[i],height[i+k])=2,ans=-1,所以该区间没有贡献

到[2,3],lcp=2,max(height[i],height[i+k])=1,ans=1,所以该区间贡献1。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4
 5 namespace suffixarray{
 6     #define FN(n) for(int i=0;i<n;i++)
 7     const int N =1E5+7;
 8     int rnk[N],sa[N],height[N],c[N];char s[N];
 9     void getsa(int n,int m,int *x=rnk,int *y=height){
10         FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i];
11         for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
12         for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){
13             for(int i=n-k;i<n;i++)y[p++]=i;
14             FN(n)if(sa[i]>=k)y[p++]=sa[i]-k;
15             FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i];
16             for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
17             swap(x,y),p=1,x[sa[0]]=0;
18             for(int i=1;i<n;i++)
19             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
20         }
21         FN(n)rnk[sa[i]]=i;
22         for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k)
23         for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++);
24     }
25 }
26 using namespace suffixarray;
27
28 int t,k,n,f[N][20];
29
30 void rmq(int *a)
31 {
32     for(int i=1;i<=n;i++)f[i][0]=a[i];
33     for(int j=1;1<<j<n;j++)for(int i=1;i<=n;i++)
34     if(i+(1<<j)-1<=n)f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
35     else break;
36 }
37 inline int find(int l,int r)
38 {
39     int k=31-__builtin_clz(r-l+1);
40     return min(f[l][k],f[r-(1<<k)+1][k]);
41 }
42
43 int main()
44 {
45     scanf("%d",&t);
46     while(t--)
47     {
48         scanf("%d%s",&k,s);
49         n=strlen(s),getsa(n+1,300);
50         height[n+1]=0;rmq(height);
51         int ans=0;
52         F(i,1,n)
53         {
54             if(i+k-1>n)continue;
55             int lcp;
56             if(i+1>i+k-1)lcp=n-sa[i];
57             else lcp=find(i+1,i+k-1);
58             lcp-=max(height[i],height[i+k]);
59             if(lcp<=0)continue;
60             ans+=lcp;
61         }
62         printf("%d\n",ans);
63     }
64     return 0;
65 }

时间: 2024-12-20 10:38:35

hdu 6194 string string string(后缀数组)的相关文章

hdu 3518 Boring counting(后缀数组)

Boring counting                                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description 035 now faced a tough problem,his english teacher gives him

hdu 4691 Front compression (后缀数组)

题目大意: 介绍了一种压缩文本的方式,问压缩前后的文本长度. 思路分析: 后缀数组跑模板然后考虑两次l r之间的lcp. 然后减掉重复的长度. 注意ans2的累加. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define maxn 200005 using namespace std; typede

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

HDU5853 Jong Hyok and String(二分 + 后缀数组)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5853 Description Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover

HDU - 4552 怪盗基德的挑战书 (后缀数组)

Description "在树最美丽的那天,当时间老人再次把大钟平均分开时,我会降临在灯火之城的金字塔前,带走那最珍贵的笑容."这是怪盗基德盗取巴黎卢浮宫的<蒙娜丽莎的微笑>这幅画时,挑战书上的内容. 但这次,怪盗基德的挑战书上出现了一串串小写字母"aaab sdfeeddd...".柯南以小学生的眼睛,超凡高中生的头脑,快速统计各种字母频率,字符串长度,并结合挑战书出现的时间等信息,试图分析怪盗基德的意图.最后,他将线索锁定在字符串的循环次数上.并且进

HDU 1403-Longest Common Substring (后缀数组)

Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", and the length is 3. Input The input contains several test ca

hdu 2459 Maximum repetition substring(后缀数组)

题目链接:hdu 2459 Maximum repetition substring 题意: 让你找一个重复最多的子串,并且输出. 题解: 这个是论文题,看的cxlove的题解,不是很理解为什么这样就能完全找完,当作结论使吧. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 namespace suffixarray{ 5 #define FN(n) f

Hdu 4117 GRE Words (后缀数组+dp)

题目大意: 求出最多能记住的单词的权值和,要求最大. 记住的规则就是上一个单词是这个单词的子串. 思路分析: 首先得声明这题是数据水了才能用sa做的. sa的复杂度最多可以达到 Orz(sumlen * sumlen) ... 所以我们sa处理的就是这个串是否是下一个串的子串,如果是就转移方程. dp[i] = max (dp[i] , dp[j] + val[i])... #include <cstdio> #include <iostream> #include <cst