ACM-ICPC 2018 焦作赛区网络预赛 H. String and Times


分析

如果height数组中存在一个区间宽度为W,且区间中每个值都大于等于H。那么这个区间对应的每个后缀,有长为H的公共前缀。也就是说这个区间产生了出现次数为W+1的长度为1~H的子串。
从大小较小的height开始计算,计算大的height时减去小height的贡献统计答案即可。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=100050;
char str[maxn];
int n;
namespace suffixArray {
    int sa[maxn],x[maxn],c[maxn],t[maxn];
    bool cmp(int u,int v,int l) {
        return x[u]==x[v]&&(u+l>n?0:x[u+l])==(v+l>n?0:x[v+l]);
	}
    void da() {
        int m=255;
        for(int i = 0; i <= m; ++i) c[i]=0;
        for(int i = 1; i <= n; ++i) c[x[i]=str[i]]++;
        for(int i = 1; i <= m; ++i) c[i]+=c[i-1];
        for(int i = n; i >= 1; --i) sa[c[x[i]]--]=i;
        for(int l = 1; l <= n; l<<=1) {
            int cnt=0;
            for(int i = n-l+1; i <= n; ++i) t[++cnt]=i;
            for(int i = 1; i <= n; ++i) {
                if(sa[i]>l) t[++cnt]=sa[i]-l;
            }
            for(int i = 0; i <= m; ++i) c[i]=0;
            for(int i = 1; i <= n; ++i) c[x[i]]++;
            for(int i = 0; i <= m; ++i) c[i]+=c[i-1];
            for(int i = n; i >= 1; --i) sa[c[x[t[i]]]--]=t[i];
            m=0,t[sa[1]]=++m;
            for(int i = 2; i <= n; ++i) {
                if(cmp(sa[i],sa[i-1],l)) t[sa[i]]=m;
                else t[sa[i]]=++m;
            }
            swap(x,t);
            if(m==n) break;
        }
    }
    int height[maxn],*rank=x;
    void calHeight() {
		for(int i = 1; i <= n; ++i) rank[sa[i]]=i;
        int h=0;
        for(int i = 1; i <= n; ++i) {
            if(h) --h;
            while(str[i+h]==str[sa[rank[i]-1]+h]) ++h;
            height[rank[i]]=h;
        }
    }
}
void deb(int *arr,string s="") {
	cout<<s<<endl;
	for(int i = 1; i <= n; ++i) {
		cout<<arr[i]<<" ";
	}
	cout<<endl;
}
int q[maxn],R[maxn],L[maxn];
ll calc(int N) {
	using suffixArray::height;
	ll ans=0;
	if(N==1) {
		ans=(ll)n*(n+1)/2;
		height[n+1]=height[1]=0;
		for(int i = 2; i <= n; ++i) {
			ans-=height[i];
		}
	}
	else {
        set<pair<int,int> > st;
		height[n+1]=height[1]=0;
		for(int i = 2; i <= n; ++i) {
            if(st.count({L[i],R[i]})) continue;
			if(R[i]-L[i]+2>=N) {
				ans+=(height[i]-max(height[L[i]-1],height[R[i]+1]));
			}
            st.insert({L[i],R[i]});
		}
	}
	return ans;
}
int main() {
	while(~scanf("%s", str+1)) {
		using namespace suffixArray;
		n=strlen(str+1);
		da();calHeight();
		int top=0;
		for(int i = n; i >= 2; --i) {
			while(top&&height[i]<=height[q[top]]) --top;
			if(top) R[i]=q[top]-1;
			else R[i]=n;
			q[++top]=i;
		}
		top=0;
		for(int i = 2; i <= n; ++i) {
			while(top&&height[i]<=height[q[top]]) --top;
			if(top) L[i]=q[top]+1;
			else L[i]=2;
			q[++top]=i;
		}
		int A,B;
		scanf("%d%d", &A,&B);
		printf("%lld\n", calc(A)-calc(B+1));
	}
	return 0;
}
posted @ 2018-09-19 16:58  sciorz  阅读(225)  评论(0编辑  收藏  举报