HDU6194(后缀数组 + rmq)
2017-09-18 15:29
211 查看
string string string
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1672 Accepted Submission(s): 482
Problem Description
Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k times
as an important string, and you need to find out how many substrings which are important strings.
Input
The first line contains an integer T (T≤100)
implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer k (k≥1)
which is described above;
the second line contain a string s (length(s)≤105).
It's guaranteed that ∑length(s)≤2∗106.
Output
For each test case, print the number of the important substrings in a line.
Sample Input
2
2
abcabc
3
abcabcabcabc
Sample Output
6
9
Source
2017 ACM/ICPC Asia Regional Shenyang Online
Recommend
liuyiding | We have carefully selected several similar problems for you: 6216 6215 6214 6213 6212
解题思路:后缀数组,先处理出height数组,然后每次取连续的k个前缀,求他们的lcp,就是在这段区间出现k次的字符串的数量,但是这些字符串并不是每个字符串都出现k次,可能会出现大于k次的情况,我们减去这部分就行,在这段区间的上边界和下边界各处理一下就行,我们可以用st表或者线段树维护一下区间lcp最小值就行。注意:每次tp数组或者rrank数组要清0,不然会影响到height的计算。。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
typedef long long LL;
int kk;
int dp[maxn][30];
int Log[maxn];
char s[maxn];
int n, m;
int a[maxn];//原数组
int rrank[maxn];//第一关键字
int Rank[maxn];//第i个前缀排第几
int tp[maxn];//第二关键字,序号为第二关键字的排名,值为对应的第一关键字的位置
int c[maxn];//用于基数排序用的数组
int Sa[maxn];//后缀数组,排名为i的后缀是哪一个后缀
int Height[maxn];//排名为i的后缀与排名为i - 1的后缀的lcp
bool judge(int *x, int loc, int ww)
{
if(x[Sa[loc]] == x[Sa[loc - 1]] && x[Sa[loc] + ww] == x[Sa[loc - 1] + ww]) return true;
else return false;
}
void suffix()
{
memset(tp, -1, sizeof(tp));//注意,一定要清0
for(int i = 1; i <= n; i++) rrank[i] = a[i];
for(int i = 1; i <= n; i++) tp[i] = i;
for(int i = 0; i <= 128; i++) c[i] = 0;
eff9
for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
for(int i = 1; i <= 128; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
m = 128;
for(int w = 1, p = 0; w <= n; w += w, m = p)
{
p = 0;
for(int i = n - w + 1; i <= n; i++) tp[++p] = i;
for(int i = 1; i <= n; i++)
{
if(Sa[i] > w) tp[++p] = Sa[i] - w;
}
for(int i = 0; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[rrank[tp[i]]]++;
for(int i = 1; i <= m; i++) c[i] += c[i - 1];
for(int i = n; i >= 1; i--) Sa[c[rrank[tp[i]]]--] = tp[i];
for(int i = 0; i <= n; i++) tp[i] = rrank[i];//重新计算rank的值
rrank[Sa[1]] = 1;
p = 1;
for(int i = 2; i <= n; i++)
{
if(judge(tp, i, w)) rrank[Sa[i]] = p;
else rrank[Sa[i]] = ++p;
}
if(p >= n) break;
}
for(int i = 1; i <= n; i++)
{
Rank[Sa[i]] = i;
}
int k = 0;
Height[1] = 0;
for(int i = 1; i <= n; i++)
{
if(k) k--;
while(a[i + k] == a[Sa[Rank[i] - 1] + k])
{
k++;
}
Height[Rank[i]] = k;
}
}
void initRmq()
{
Log[0] = -1;
for(int i = 1; i <= n; i++)
{
if((i&(i - 1)) == 0) Log[i] = Log[i - 1] + 1;
else Log[i] = Log[i - 1];
dp[i][0] = Height[i];
}
for(int j = 1; j <= 25; j++)
{
for(int i = 1; i <= n && (i + (1<<j) - 1) <= n; i++)
{
dp[i][j] = min(dp[i][j - 1], dp[i + (1<<(j - 1))][j - 1]);
}
}
}
int rmq(int l, int r)
{
int d = r - l + 1;
d = Log[d];
return min(dp[l][d], dp[r - (1<<d) + 1][d]);
}
void init()
{
n = strlen(s);
memset(Height, 0, sizeof(Height));
memset(a, -1, sizeof(a));//注意,一定要重置。在这里wa了无数次
for(int i = 0; i < n; i++)
{
a[i + 1] = s[i];
}
}
int main()
{
//freopen("C:\\Users\\creator\\Desktop\\in1.txt","r",stdin) ;
//freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &kk);
scanf("%s", s);
init();
suffix();
initRmq();
LL ans = 0;
if(kk == 1)
{
for(int i = 1; i <= n; i++)
{
LL value = (LL)(n - Sa[i] + 1);
LL value1, value2;
value1 = (LL)Height[i];
if(i + 1 <= n) value2 = (LL)Height[i + 1];
else value2 = 0;
LL Max = max(value1, value2);
if(value > Max) ans += value - Max;
}
}
else
{
for(int i = 1; i + 1 <= n && i + (kk - 1) <= n; i++)
{
LL value = (LL)rmq(i + 1, i + (kk - 1));
LL value1 = (LL)rmq(i, i + (kk - 1));
LL value2;
if(i + kk <= n) value2 = (LL)rmq(i + 1, i + kk);
else value2 = 0;
LL Max = max(value1, value2);
if(value > Max) ans += value - Max;
}
}
printf("%I64d\n", ans);
}
return 0;
}
相关文章推荐
- hdu6194 string string string 后缀数组 + RMQ
- HDU 5558 (后缀数组 二分 RMQ)
- (模板)后缀数组(lcp和rmq)
- HDU 2459 PKU 3693 Maximum repetition substring 后缀数组 RMQ
- hdu5008 Boring String Problem,2014西安网络赛B题,后缀数组,RMQ
- hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq
- hdu 5008 (后缀数组 + rmq +二分)
- URAL1297Palindrome(最长回文子串 、后缀数组最长公共前缀+RMQ)
- HDU 5008 Boring String Problem 后缀数组 RMQ
- 51nod 1732 51nod婚姻介绍所 后缀数组 + rmq
- SPOJ 687 Repeats 后缀数组+暴力+rmq
- hdu 4691 最长公共前缀 后缀数组 +lcp+rmq
- POJ 3693 Maximum repetition substring 后缀数组 暴力 rmq
- uval1297 Palindrome 后缀数组求最长回文字串,lcp,rmq
- POJ 3693 Maximum Repetition Substring <后缀数组 + RMQ>
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
- BZOJ 3277: 串/ BZOJ 3473: 字符串 ( 后缀数组 + RMQ + 二分 )
- HDU 6194 string string string 后缀数组 + RMQ(线段树)
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
- BZOJ 3230 相似子串|后缀数组|RMQ