[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 BA≤times≤B). 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^6∑length(S)≤2×106,
1 le A le B le length(S)1≤A≤B≤length(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