zoukankan      html  css  js  c++  java
  • 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
    ", calc(A)-calc(B+1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android ViewPager用法小结
    HDU1212 Big Number 【同余定理】
    1051. Pop Sequence (25)
    FFmpeg源码结构图
    oracle访问不同用户的表不添加用户名前缀
    window7开启Administrator账户
    Window下对nodejs多版本管理GNVM
    基于Centos7.5搭建Docker环境
    grep与孪生兄弟egrep差异
    Linux编译步骤概述
  • 原文地址:https://www.cnblogs.com/sciorz/p/9675485.html
Copyright © 2011-2022 走看看