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

Posted jiaqi666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 imes 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
",GetK(k,n)-GetK(k+m+1,n));  //至少出现n次的字串数-至少出现m+1次的字串数
    }
}
int main(){
    Run();
    return 0;
}

 




以上是关于[2018 ACM-ICPC 焦作赛区网络赛] H - String and Times(后缀自动机)的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 焦作赛区网络预赛 H题 String and Times(SAM)

ACM-ICPC 2018 焦作赛区网络预赛 Solution

ACM-ICPC 2018 焦作赛区网络预赛 HL

ACM-ICPC 2018 焦作赛区网络预赛 I题(滑稽)

ACM-ICPC 2018 焦作赛区网络预赛 A Magic Mirror(签到)

ACM-ICPC 2018 焦作赛区网络预赛