1. 程式人生 > >ACM-ICPC 2018 焦作賽區網路預賽 H. String and Times (字尾自動機&字尾陣列)

ACM-ICPC 2018 焦作賽區網路預賽 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 \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;
}