[2018 ACM-ICPC 焦作赛区网络赛] H - String and Times(后缀自动机)

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

Input

Input has multiple test cases.

For each line, there is a string SS, two integers AA and BB.

\sum length(S) \le 2 \times 10^6length(S)2×106,

1 \le A \le B \le length(S)1ABlength(S)

Output

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

样例输入

AAA 2 3
ABAB 2 2

例输

2
3
题意:给你任意一个由大写字母构成的字符串,统计其出现n到m次的字串个数
思路:这道题和HDU 6194很像,那道题是要统计恰好出现k次的字串个数,是用后缀自动机做的,那么这道题其实可以直接把最后询问的操作改成GetK(k,n)-GetK(k+m+1,n))即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MaxN=2e5+100;
const ll MAXN = MaxN;
ll cntA[MaxN],cntB[MaxN],tsa[MAXN],A[MAXN],B[MAXN];
ll sa[MAXN],Rank[MAXN],h[MAXN];
char ch[MAXN];
struct Node{
    ll val,index;
    Node(ll val_,ll index_):val(val_),index(index_){
    }
    bool operator < (const Node b)const{
        if (val==b.val){
            return b.index<index;
        }
        return b.val<val;
    }
};
priority_queue<Node>pq;
void GetSa(char *ch,ll *sa,ll *rank,ll n){
 
    for(ll i=0;i<MaxN;i++)  cntA[i]=0;
    for(ll i=1;i<=n;i++)   cntA[ch[i]]++;
    for(ll i=1;i<=MaxN;i++) cntA[i]+=cntA[i-1];
    for(ll i=n;i;i--)  sa[cntA[ch[i]]--]=i;
    rank[sa[1]]=1;
    for(ll i=2;i<=n;i++){
        rank[sa[i]]=rank[sa[i-1]];
        if(ch[sa[i]]!=ch[sa[i-1]])  rank[sa[i]]++;
    }
    for(ll l=1;rank[sa[n]]<n;l<<=1){
        for(ll i=0;i<MaxN;i++)  cntA[i]=0;
        for(ll i=0;i<MaxN;i++)  cntB[i]=0;
        for(ll i=1;i<=n;i++){
            cntA[A[i]=rank[i]]++;
            cntB[B[i]=(i+l<=n)?rank[i+l]:0]++;
        }
        for(ll i=1;i<MaxN;i++)   cntB[i]+=cntB[i-1];
        for(ll i=n;i;i--)  tsa[cntB[B[i]]--]=i;
        for(ll i=1;i<MaxN;i++)  cntA[i]+=cntA[i-1];
        for(ll i=n;i;i--)  sa[cntA[A[tsa[i]]]--]=tsa[i];
        rank[sa[1]]=1;
        for(ll i=2;i<=n;i++){
            rank[sa[i]]=rank[sa[i-1]];
            if(A[sa[i]]!=A[sa[i-1]] || B[sa[i]]!=B[sa[i-1]])    rank[sa[i]]++;
        }
    }
}
 
void GetHeight(char *ch,ll *sa,ll *rank,ll *height,ll n){
 
    GetSa(ch,sa,rank,n);
    for(ll i=1,j=0;i<=n;i++){
        if(j)   j--;
        while(ch[i+j]==ch[sa[rank[i]-1]+j]) j++;
        height[rank[i]]=j;
    }
}
ll GetK(ll k,ll n){
    ll ans=0;
    k--;
    if(k==0){
        for(ll i=1;i<=n;++i)   ans=ans+(n-sa[i]+1-h[i]);
        return ans;
    }
    while (!pq.empty())pq.pop();
    for (ll i=2;i<=n;i++){
        while (!pq.empty()&&pq.top().index<i-k+1)pq.pop();
        pq.push(Node(h[i],i));
        if (i>k){
            ll top = pq.top().val;
            ll last = h[i-k];
            ans +=max((ll)0,top-last);
        }
    }
    return ans;
}
 
void Run(){
    ll n,k,m;
    while(~scanf("%s %lld %lld",ch+1,&k,&m)){
        n=strlen(ch+1);
        GetHeight(ch,sa,Rank,h,n);
        printf("%lld\n",GetK(k,n)-GetK(k+m+1,n));  //至少出现n次的字串数-至少出现m+1次的字串数
    }
}
int main(){
    Run();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jiaqi666/p/9655165.html