zoukankan      html  css  js  c++  java
  • BZOJ2119 股市的预测 字符串 SA ST表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9069171.html

    题目传送门 - BZOJ2119

    题意

      给定一个股票连续$n$个时间点的价位,问有多少段股票走势在间隔$m$单位时间之后重现?

      $nleq 5 imes 10^4,mleq 10$

    题解

      和 http://www.cnblogs.com/zhouzhendong/p/9025092.html 此题十分类似。

      这里稍微讲讲本题的不同之处。

      首先相邻值求差,转换成字符串匹配。

      然后,由于要间隔$m$个字符,所以我们在找关键点的对应点的时候要稍微改一改。

      对于得到的$lcs$和$lcp$,在计算的时候有一点小小的注意点。

      详见代码。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    int n,m,a[N],tot=0;
    map <int,int> mp;
    int SA[N],rank[N],tmp[N],height[N],tax[N];
    int ST[N][20];
    void Sort(int n,int m){
    	for (int i=0;i<=m;i++)
    		tax[i]=0;
    	for (int i=1;i<=n;i++)
    		tax[rank[i]]++;
    	for (int i=1;i<=m;i++)
    		tax[i]+=tax[i-1];
    	for (int i=n;i>=1;i--)
    		SA[tax[rank[tmp[i]]]--]=tmp[i];
    }
    bool cmp(int rk[],int x,int y,int w){
    	return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
    }
    void Suffix_Array(int s[],int n){
    	memset(SA,0,sizeof SA);
    	memset(tmp,0,sizeof tmp);
    	memset(rank,0,sizeof rank);
    	memset(height,0,sizeof height);
    	for (int i=1;i<=n;i++)
    		rank[i]=s[i],tmp[i]=i;
    	int m=tot+1;
    	Sort(n,m);
    	for (int w=1,p=0;p<n;w<<=1,m=p){
    		p=0;
    		for (int i=n-w+1;i<=n;i++)
    			tmp[++p]=i;
    		for (int i=1;i<=n;i++)
    			if (SA[i]>w)
    				tmp[++p]=SA[i]-w;
    		Sort(n,m);
    		swap(rank,tmp);
    		rank[SA[1]]=p=1;
    		for (int i=2;i<=n;i++)
    			rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;
    	}
    	for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)
    		for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);
    	height[1]=0;
    }
    void Get_ST(int n){
    	memset(ST,0,sizeof ST);
    	for (int i=1;i<=n;i++){
    		ST[i][0]=height[i];
    		for (int j=1;j<20;j++){
    			ST[i][j]=ST[i][j-1];
    			if (i-(1<<(j-1))>0)
    				ST[i][j]=min(ST[i][j],ST[i-(1<<(j-1))][j-1]);
    		}
    	}
    }
    int Query(int L,int R){
    	int val=floor(log(R-L+1)/log(2));
    	return min(ST[L+(1<<val)-1][val],ST[R][val]);
    }
    int LCP(int x,int y){
    	x=rank[x],y=rank[y];
    	return Query(min(x,y)+1,max(x,y));
    }
    int LCS(int x,int y){
    	return LCP(n*2+2-x,n*2+2-y);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	n--;
    	mp.clear();
    	for (int i=1;i<=n;i++){
    		a[i]=a[i+1]-a[i];
    		if (mp[a[i]]==0)
    			mp[a[i]]=++tot;
    		a[n*2+2-i]=a[i]=mp[a[i]];
    	}
    	a[n+1]=tot+1;
    	Suffix_Array(a,n*2+1);
    	Get_ST(n*2+1);
    	LL ans=0;
    	for (int L=1;L<=n;L++)
    		for (int i=1;i+L+m<=n;i+=L){
    			int x=i,y=i+L+m;
    			int lcp=min(LCP(x,y),L),lcs=min(LCS(x,y),L);
    			int len=lcp+lcs-(lcp>0&&lcs>0);
    			ans+=max(len-L+1,0);
    		}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    两个序列最大子集公共和问题
    两个随机变量相关系数
    多项分布的定义
    算法分析结课总结回溯算法
    潜语义分析LSA相比向量空间模型VSM改变了什么
    类对象的声明和类对象指针的申请的种种
    C#中 常用的方法
    转:GridView鼠标移动行变色 (http://www.cnblogs.com/lovenets/articles/808071.html)[同ceng]
    WinForm 获取指定行列的Value
    华丽丽的分隔符
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/9069171.html
Copyright © 2011-2022 走看看