2018 焦作网络赛 H String and Times

题意:

给出一个字符串,和一个上下界,求所有子串中出现次数恰好介于上下界的个数。

题解:

假设上下界为x、y,我们计算出出现次数大于k的数目cal(k),那么cal(x)-cal(y+1)就是答案。

先上后缀数组板子求出rank、sa和height数组

我们按rank从小到大排序,相邻k个位一组,即1~k、2~k+1、3~k+2、4~k+3。。。。。。

对于1~k,假设这一组的height的最小值为c,那么就有c个字符串的出现次数至少为k,这是显然易见的。

对于2~k+1,假设这一组的height的最小值为c’,如果c’>c那么又多出(c’-c)个字符串的出现次数至少为k,

如果c’<c,那么对答案没有贡献。

总结一下,如果本组height的最小值比上一组多,那么对答案贡献差值个,如果比上一组少,则没有贡献。

代码:

#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lower_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

char s[N];
int sa[N],t[N],t2[N],c[N],n,rak[N],height[N],f[18][N];

void build_sa(int m,char *s)
{
    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 k=0;
    for (int i=0;i<n;i++)rak[sa[i]]=i;
    for (int i=0;i<n;i++)
    {
        if (k)k--;
        if (!rak[i])continue;
        int j=sa[rak[i]-1];
        while (s[i+k]==s[j+k])k++;
        height[rak[i]]=k;
    }
    for (int i=0;i<n;i++) f[0][i]=height[i];
    for (int j=1;(1<<j)<n;j++)
        for (int i=0;i<n;i++)if (i+(1<<(j-1)) <n)
            f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]);
}

int qu(int x,int y)
{
    if (x==y) return f[0][x];
    int k=31-__builtin_clz(y-x);
    return min(f[k][x],f[k][y-(1<<k)+1]);
}

LL cal(int k)
{
    if (k==1)
    {
        LL res=n-sa[1]-1;
        for (int i=2;i<n;i++) res+=n-sa[i]-height[i]-1;
        return res;
    }else
    if (k>n)return 0;else
    {
        LL res=0,m=0;
        for (int i=0;i+k-1<n;i++)
        {
            int t=qu(i+1,i+k-1);
            if (t>m) res+=t-m;
            m=t;
        }
        return res;
    }
}

int main()
{
    while (~scanf("%s",s))
    {
        n=strlen(s); s[n]='#'; n++;
        build_sa(200,s);
        getheight();
        int x,y;
        scc(x,y);
        printf("%lld\n",cal(x)-cal(y+1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/nudt_spy/article/details/82780118