String and Times

String and Times

时间限制: 1 Sec  内存限制: 128 MB

题目描述

Now you have a string consists of uppercase letters, two integers A and B. We call a substring wonderful substring when the times it appears in that string is between A and B (A ≤ times ≤ B). Can you calculate the number of wonderful substrings in that string?

输入

Input has multiple test cases.
For each line, there is a string S, two integers A and B.
∑Length(S)≤2×10^6,1≤A≤B≤length(S) 

输出

For each test case, print the number of the wonderful substrings in a line.

样例输入

AAA 2 3
ABAB 2 2

样例输出

2
3

题意:给定字符串,求出现次数在[l,r]内的不同字符串的个数。
思路:首先考虑求出现次数大于等于k次的字符串个数。后缀数组的height数组的定义为某个后缀串和它前一个后缀串(此处“前一个”意思是按照字典序的排名来的前一个)的最长公共前缀,那么height数组里若有连续的k-1个数的最小值为min,就代表有一个长度为min的字符串最少出现了k次。
#include<bits/stdc++.h>
#define INF LLONG_MAX/2
#define lson (rt*2)
#define rson (rt*2+1)
using namespace std;
const int N = 2e5+50;
char s[N];

struct SuffixArray
{
    int sa[N],rank[N],height[N],cnt[N],a1[N],a2[N],n,m,*x,*y;
    void sort()
    {
        for(int i=0; i<m; i++) cnt[i]=0;
        for(int i=0; i<n; i++) cnt[x[i]]++;
        for(int i=1; i<m; i++) cnt[i]+=cnt[i-1];
        for(int i=n-1; i>=0; i--) sa[--cnt[x[y[i]]]]=y[i];
    }
    void build(char *s,int c_size)
    {
        n=strlen(s);
        m=c_size;
        x=a1;
        y=a2;
        for(int i=0; i<n; i++) x[i]=s[i],y[i]=i;
        x[n]=y[n]=-1;
        sort();
        for(int k=1; k<=n; k<<=1)
        {
            int p=0;
            for(int i=n-k; i<n; i++) y[p++]=i;
            for(int i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            sort();
            p=0;
            std::swap(x,y);
            x[sa[0]]=0;
            for(int i=1; i<n; i++)
            {
                if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) p++;
                x[sa[i]]=p;
            }
            if(p+1>=n) break;
            m=p+1;
        }
        for(int i=0; i<n; i++) rank[sa[i]]=i;
        height[0]=0;
        int k=0;
        for(int i=0; i<n; i++)
        {
            if(k) k--;
            if(rank[i]==0) continue;
            int j=sa[rank[i]-1];
            while(i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++;
            height[rank[i]]=k;
        }
    }
} SA;

struct node
{
    long long val;
    int l,r;
}tree[N<<2];
void build(int rt,int l,int r)
{
    int mid=(l+r)>>1;
    tree[rt].l=l,tree[rt].r=r;
    tree[rt].val=INF;
    if(l==r)
    {
        tree[rt].val=SA.height[l];
        return ;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    tree[rt].val=min(tree[lson].val,tree[rson].val);
}
int query(int rt,int l,int r)
{
    int mid=(tree[rt].l+tree[rt].r)/2;
    if(tree[rt].l==l&&tree[rt].r==r)return tree[rt].val;
    if(r<=mid)return query(lson,l,r);
    else
        if(l>mid)return query(rson,l,r);
    else
        return min(query(lson,l,mid),query(rson,mid+1,r));
}

long long cal(int k,int n)   //求出现k次以上的字符串的个数
{
    long long ans=0;
    if(k==1)
    {
        for(int i=0;i<n;i++) ans+=(n-SA.sa[i]-SA.height[i]);
        return ans;
    }
    int l=1,r=1+k-2;
    int pre=0;
    while(r<n)//处理全部长度为k-1的连续区间
    {
        int now=query(1,l,r);
        if(now>=pre) ans+=now-pre;//要注意减去上一个区间的贡献
        pre=now;
        l++,r++;
    }
    return ans;
}
int main()
{
    while(scanf("%s",s)!=EOF)
    {
        int L,R;
        scanf("%d%d",&L,&R);
        int ls=strlen(s);
        SA.build(s,255);
        build(1,1,ls-1);
        printf("%lld\n",cal(L,ls)-cal(R+1,ls));
    }
    return 0;
}
View Code

 

 
posted @ 2019-08-03 20:46  1371767389  阅读(237)  评论(0编辑  收藏  举报