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;
    }
    
  • 相关阅读:
    Layui数据表格的使用
    单选按钮和下拉框默认选中
    平方探测法处理散列函数冲突
    ssh框架整合笔记---配置文件
    第二十九个知识点:什么是UF-CMA数字签名的定义?
    第二十八个知识点:什么是公钥密码学的IND-CCA安全定义?
    第二十七个知识点:什么是对称密码加密的AEAD安全定义?
    第二十六个知识点:描述NAF标量乘法算法
    第二十五个知识点:使用特殊的素数定义$GF(p)$和$GF(2^n)$的方法。
    第二十四个知识点:描述一个二进制m组的滑动窗口指数算法
  • 原文地址:https://www.cnblogs.com/sciorz/p/9675485.html
Copyright © 2011-2022 走看看