HDU 6194 string string string (后缀数组+线段树)

版权声明:欢迎大佬指正! 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;
}

猜你喜欢

转载自blog.csdn.net/sinat_36215255/article/details/82229023
今日推荐