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
相關文章
相關標籤/搜索