ACM-ICPC 2018 焦作賽區網路預賽 H. String and Times (字尾自動機&字尾陣列)
阿新 • • 發佈:2018-12-10
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 \times 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
題目來源
和去年瀋陽網賽的A題類似
字尾自動機的板子題,用至少出現A次的的次數減掉至少出現B+1的次數就是答案
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 200005; typedef long long ll; char s[N]; struct SAM{ int p,q,np,nq,cnt,lst,a[N][26],l[N],f[N],tot; int Tr(char c){return c-'A';} int val(int c){return l[c]-l[f[c]];} SAM(){cnt=0;lst=++cnt;} void Initialize(){ memset(l,0,sizeof(int)*(cnt+1)); memset(f,0,sizeof(int)*(cnt+1)); for(int i=0;i<=cnt;i++)for(int j=0;j<26;j++)a[i][j]=0; cnt=0;lst=++cnt; } void extend(int c){ p=lst;np=lst=++cnt;l[np]=l[p]+1; while(!a[p][c]&&p)a[p][c]=np,p=f[p]; if(!p){f[np]=1;} else{ q=a[p][c]; if(l[p]+1==l[q])f[np]=q; else{ nq=++cnt;l[nq]=l[p]+1; memcpy(a[nq],a[q],sizeof(a[q])); f[nq]=f[q]; f[np]=f[q]=nq; while(a[p][c]==q)a[p][c]=nq,p=f[p]; } } } int b[N],x[N],r[N]; void build(){ int len=strlen(s+1); for(int i=1;i<=len;i++)extend(Tr(s[i])); memset(r,0,sizeof(int)*(cnt+1)); memset(b,0,sizeof(int)*(cnt+1)); for(int i=1;i<=cnt;i++)b[l[i]]++; for(int i=1;i<=len;i++)b[i]+=b[i-1]; for(int i=1;i<=cnt;i++)x[b[l[i]]--]=i; for(int i=p=1;i<=len;i++){p=a[p][Tr(s[i])];r[p]++;} for(int i=cnt;i;i--)r[f[x[i]]]+=r[x[i]]; } void solve(){ ll ans1=0,ans2 = 0; int A,B; build(); scanf("%d %d",&A,&B); for(int i=1;i<=cnt;i++)if(r[x[i]] >= A) ans1 += val(x[i]); for(int i=1;i<=cnt;i++)if(r[x[i]] >= B + 1) ans2 += val(x[i]); printf("%lld\n",ans1 - ans2); } }sam; int main(void){ while(scanf("%s",s + 1) != EOF){ sam.Initialize(); sam.solve(); }return 0; }
字尾陣列寫法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MaxN = 200005;
const int MAXN = 200005;
int cntA[MAXN],cntB[MAXN],tsa[MAXN],A[MAXN],B[MAXN];
int sa[MAXN],Rank[MAXN],h[MAXN];
char ch[MAXN];
struct Node
{
int val,index;
Node(int val_,int 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,int *sa,int *rank,int n){
for(int i=0;i<MaxN;i++) cntA[i]=0;
for(int i=1;i<=n;i++) cntA[ch[i]]++;
for(int i=1;i<=MaxN;i++) cntA[i]+=cntA[i-1];
for(int i=n;i;i--) sa[cntA[ch[i]]--]=i;
rank[sa[1]]=1;
for(int i=2;i<=n;i++){
rank[sa[i]]=rank[sa[i-1]];
if(ch[sa[i]]!=ch[sa[i-1]]) rank[sa[i]]++;
}
for(int l=1;rank[sa[n]]<n;l<<=1){
for(int i=0;i<MaxN;i++) cntA[i]=0;
for(int i=0;i<MaxN;i++) cntB[i]=0;
for(int i=1;i<=n;i++){
cntA[A[i]=rank[i]]++;
cntB[B[i]=(i+l<=n)?rank[i+l]:0]++;
}
for(int i=1;i<MaxN;i++) cntB[i]+=cntB[i-1];
for(int i=n;i;i--) tsa[cntB[B[i]]--]=i;
for(int i=1;i<MaxN;i++) cntA[i]+=cntA[i-1];
for(int i=n;i;i--) sa[cntA[A[tsa[i]]]--]=tsa[i];
rank[sa[1]]=1;
for(int 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,int *sa,int *rank,int *height,int n){
GetSa(ch,sa,rank,n);
for(int 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(int k,int n){
ll ans=0;
k--;
if(k==0){
for(int i=1;i<=n;++i) ans=ans+(n-sa[i]+1-h[i]);
return ans;
}
while (!pq.empty())pq.pop();
for (int 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){
int top = pq.top().val;
int last = h[i-k];
ans +=max(0,top-last);
}
}
return ans;
}
int AA,BB;
void Run(){
int n,k;
n=strlen(ch+1);
GetHeight(ch,sa,Rank,h,n);
ll ans1 = GetK(AA,n);
ll ans2 = GetK(BB+1,n);
printf("%lld\n",ans1 - ans2);
}
int main(void){
while(scanf("%s %d %d",ch + 1,&AA,&BB) != EOF) {
Run();
}
return 0;
}