zoukankan      html  css  js  c++  java
  • 【BZOJ 2119】股市的预测(SAM)

    SAM很好用的啊。。。

    传送门

    双倍经验:L-Gap Substrings

    基本做法类似,这道题的差分改掉,map 改掉就好了QWQ

    noteskey

    反正就是先差分一下,然后把首项丢掉(没有比较的对象自然就不算趋势了)

    然后就是建 SAM ,做法如下(抄了自己的题解 QWQ)

    转化:给出一个序列,求多少个相距为 m 的子串是相同的

    因为 v 的长度是已知的 m ,我们甚至都不用在乎 v 是什么,只需要找到有多少个相距为 m 的相同字符串就好了

    枚举长度

    于是我们考虑和优秀的拆分(就是可以暴力 hash 水的那道)一样的做法,枚举两个相同字符串的长度 j

    然后我们枚举到一个位置 l 之后, r 其实就确定了, (r=l+m+j) ,然后我们求出以 l、r 结尾的 lcs ,以及以 l、r 开头的 lcp 的长度,分别记为 lcs、lcp (就这么标注吧...)

    这样的话我们发现只要 lcs+lcp-1>=j ,(j 也就是我们枚举的长度),那么当前的 l、r 就是一个可行解

    这里为什么要 -1 ?因为我们计算 lcp 和 lcs 的时候 l、r 位置的字母算了两次啊...

    至于 lcp 等于 0 的话,lcs 必然也等于 0 ,这时候必然不满足条件,得到长度为 -1 也没关系...

    一点优化

    但是我们发现这样的复杂度有点锅...(这不是已经 n^2 了么...) 那么我们发现求出来的 lcp 和 lcs 没有充分利用,仅仅是拿来判断当前 l、r 是否可行了

    其实我们可以让 lcp 和 lcs 分别与 j 取 min ,然后判断某一块区域解的合法性,因为 l、r 一起左右移动的话,中间的距离是不变的啊...

    这样的话我们算出当前长度为 2j 的区域的 u 长度为 j 的解,然后跳到下一个区域就好了

    所以说 (lcp+lcs-1-j+1=lcp+lcs-j) 就是当前可以计入答案的解

    至于为什么要和 j 取 min ? 因为我们下一次要让 l 加上 j 跳到下一个区域,和 j 取 min 可以保证答案不算重

    这样做的复杂度 是 (O({nover 1}+{nover 2}+...+{nover n})=O(n({1}+{1over 2}+...+{1over n}))≈O(n~log~n)) ,只能说是这个级别的复杂度,证明需要用调和级数吧(我不会)

    求 lcp 和 lcs

    那么接下来的任务也就是求 lcp 和 lcs 的长度了

    我们都知道一个字符串内 两个子串的 lcp 就等于他们 (endpos) 所在节点的 lca ,然后 lcp 长度就是 (len[lca]) 了,那么我们把 parent 树建出来,就可以开森的在上面树剖找 lca 啦~

    这样的复杂度是... (O(n~log^2~n))

    好卡啊...那么我们用 st 表优化一下求 lca 可能就是一个 (O(n~log~n)) 的算法了吧...

    watch out

    数组别忘了清零...这个我倒是没犯

    但是我 TM 调了一个下午的原因就是 (insert) 的时候 (s[i]) 没有减去 $'a' $ ,结果数组越界出现了无限可能啊!mmp,千万不要学我这个代码都打不来的大菜鸡...

    卡常的话这道题根本不需要(那些技巧留着做 Ynoi 吧~)

    code

    可读性极差,不建议 copy

    //by Judge
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define Rg register
    #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
    #define go(G,u) for(Rg int i=G.head[u],v=G.e[i].to;i;v=G.e[i=G.e[i].nxt].to)
    #define ll long long
    using namespace std;
    const int M=2e5+3;
    typedef int arr[M];
    #ifndef Judge
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    #endif
    char buf[1<<21],*p1=buf,*p2=buf;
    inline int read(){ int x=0,f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    } inline void reads(string& s){ char c=getchar();
    	for(;!isalpha(c);c=getchar()); s=" ";
    	for(;isalpha(c);c=getchar()) s+=c;
    } int n,m,a[M]; ll ans;
    struct SAM{ int cnt,las,tim; SAM(){las=cnt=1;}
    	int st[M][19]; arr fa,len,lg,pos,id; map<int,int> to[M];
    	inline void insert(int c,int now){
    		int p=las,np=las=++cnt; len[np]=len[p]+1;
    		for(;p&&!to[p][c];p=fa[p]) to[p][c]=np; pos[now]=np;
    		if(!p) return fa[np]=1,void(); int q=to[p][c];
    		if(len[q]==len[p]+1) return fa[np]=q,void();
    		int nq=++cnt; len[nq]=len[p]+1,fa[nq]=fa[q];
    		fa[q]=fa[np]=nq,to[nq]=to[q];
    		for(;p&&to[p][c]==q;p=fa[p]) to[p][c]=nq;
    	}
    	struct Gr{ int pat,head[M]; struct Edge{ int to,nxt; }e[M];
    		inline void add(int u,int v){e[++pat]={v,head[u]},head[u]=pat;}
    	}G;
    	inline int Min(int x,int y){return len[x]<len[y]?x:y;}
    	void dfs(int u){ st[++tim][0]=u,id[u]=tim; go(G,u) dfs(v),st[++tim][0]=u; }
    	inline void calc(){ fp(i,1,cnt) G.add(fa[i],i); dfs(1); fp(i,2,tim) lg[i]=lg[i>>1]+1;
    		fp(j,1,lg[tim]) fp(i,1,tim-(1<<j)+1) st[i][j]=Min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    	}
    	inline int get(int x,int y,int k=0){
    		x=id[pos[x]],y=id[pos[y]]; if(x>y) swap(x,y); k=lg[y-x+1];
    		return len[Min(st[x][k],st[y-(1<<k)+1][k])];
    	}
    }p,q;
    inline int Min(int x,int y){return x<y?x:y;}
    int main(){ n=read()-1,m=read();
    	fp(i,0,n) a[i]=read();
    	fd(i,n,1) a[i]-=a[i-1];
    	fp(i,1,n) p.insert(a[i],i);
    	fd(i,n,1) q.insert(a[i],i);
    	p.calc(),q.calc();
    	fp(j,1,(n-m)>>1)
    		for(Rg int i=1;i+j+m<=n;i+=j){
    			int l=i,r=i+j+m;
    			int lcp=Min(q.get(l,r),j);
    			int lcs=Min(p.get(l,r),j);
    			int len=lcs+lcp-1;
    			if(len>=j) ans+=len-j+1;
    		} return !printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南
    《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南
    《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南
    使用Jasmine和karma对传统js进行单元测试
    《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南
    《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南
    nginx 基于IP的多虚拟主机配置
    Shiro 框架的MD5加密算法实现原理
    项目实战:Qt+OSG三维点云引擎(支持原点,缩放,单独轴或者组合多轴拽拖旋转,支持导入点云文件)
    实用技巧:阿里云服务器建立公网物联网服务器(解决阿里云服务器端口,公网连接不上的问题)
  • 原文地址:https://www.cnblogs.com/Judge/p/10666952.html
Copyright © 2011-2022 走看看