版权声明:欢迎大佬指正! https://blog.csdn.net/sinat_36215255/article/details/82229023
题目https://cn.vjudge.net/problem/HDU-6194
没想到怎么用height数组求个数,看了看题解结合自己写的才明白,
妙啊。
我们按照height数组的特点,height【i+1】到height【i+k-1】中的最小值便是在sa【i】 到sa【i+k-1】这k个后缀串中都出现过的子串长度,也就是说这个子串至少出现了k次,但是题目中要求这个子串必须标准出现k次,于是我们再看这子串有没有出现在sa【i-1】或者sa [i+k] 中,即看max(height【i-1】,heigh【i+k】),我们将出现了的减去,剩下的即是,标准出现k次的,如果小于0 的话说明当前区间没有满足要求的子串。
当k=1时,按照原来的办法求就不好求了,但是我们用同样的思路,先求一个当前满足要求的串的长度,那不就是 n - sa[i] 吗,然后按照同样的思路再减去 max(height【i-1】,heigh【i+k】)
借鉴https://blog.csdn.net/My_stage/article/details/77936442
代码如下:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e5+50;
char s[MAXN];
int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n;
int height[MAXN], rankk[MAXN];
void DA(int m)
{
int i, *x = t, *y = t2;
for ( i = 0; i < m; i++) c[i] = 0;
for ( i = 0; i < n; i++) c[x[i] = s[i]]++;
for ( i = 1; i < m; i++) c[i] += c[i - 1];
for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1){
int p = 0;
for (i = n - k; i < n; i++)
y[p++] = i;
for (i = 0; i < n; i++){
if (sa[i] >= k)
y[p++] = sa[i] - k;
}
for (i = 0; i < m; i++) c[i] = 0;
for (i = 0; i < n; i++)
c[x[y[i]]]++;
for (i = 0; i < m; i++)
c[i] += c[i - 1];
for (i = n - 1; i >= 0; i--)
sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[sa[0]] = 0;
for (i = 1; i < n; i++){
x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
}
if (p >= n) break;
m = p;
}
}
void getHeight()
{
int i, j, k = 0;
for (i = 0; i < n; i++) rankk[sa[i]] = i;
for (i = 0; i < n; i++){
if (k) k--;
j = sa[rankk[i] - 1];
while (s[i + k] == s[j + k]) k++;
height[rankk[i]] = k;
}
}
int mi[MAXN<<2];
void build(int rt,int l,int r)
{
if(l == r)
{
mi[rt]=height[l];
return;
}
int mid =(l+r)>>1;
build(rt<<1|1,mid+1,r);
build(rt<<1,l,mid);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
int query(int ql,int qr,int l,int r,int rt)
{
if(ql<=l && qr>=r)
return mi[rt];
int mid=(l+r)>>1;
int ans=1e9;
if(mid>=ql) ans= query(ql,qr,l,mid,rt<<1);
if(mid<qr) ans=min(ans,query(ql,qr,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);
n = len+1;
DA(200);
getHeight();
build(1,1,len);
height[len+1]=0;
if(k>len)
{
printf("0\n");
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+k-1<=len; i++)
{
ans+=max(query(i+1,i+k-1,1,len,1)-max(height[i],height[i+k]),0);
}
printf("%d\n",ans);
}
return 0;
}