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({n\over 1}+{n\over 2}+...+{n\over n})=O(n({1}+{1\over 2}+...+{1\over 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\n",ans);
}

【BZOJ 2119】股市的预测(SAM)的更多相关文章

  1. BZOJ 2119: 股市的预测 [后缀数组 ST表]

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss ...

  2. BZOJ 2119: 股市的预测 SA

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 434  Solved: 200[Submit][Status][Discuss ...

  3. bzoj 2119: 股市的预测

    Description 墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势.股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况.经过长时 ...

  4. ●BZOJ 2119 股市的预测

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2119 题解: 这个题很好的. 首先把序列转化为差分序列,问题转化为找到合法的子序列,使得去除 ...

  5. bzoj 2119 股市的预测——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 就是找差分序列上中间差 m 的相等的两段. 考虑枚举这样一段的长度 L .可以把序列分 ...

  6. bzoj 2119 股市的预测 —— 枚举关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 思路就是对于这个形如 ABA 的串,枚举 A 的长度,并按照长度分出几块,找到一些关键 ...

  7. BZOJ 2119 股市的预测 (后缀数组+RMQ)

    题目大意:求一个字符串中形如$ABA$的串的数量,其中$B$的长度是给定的 有点像[NOI2016]优秀的拆分这道题 先对序列打差分,然后离散,再正反跑$SA$,跑出$st$表 进入正题 $ABA$串 ...

  8. BZOJ 2119 股市的预测(后缀数组)

    首先要差分+离散化. 然后就是求形如ABA的串有多少,其中B的长度确定为k. 我们用到了设置关键点的思想.我们枚举A的长度L.然后在\(1,1+L,1+L*2,1+L*3...\)设置关键点.然后我们 ...

  9. BZOJ 2119: 股市的预测 (Hash / 后缀数组 + st表)

    转博客大法好 自己画一画看一看,就会体会到这个设置关键点的强大之处了. CODE(sa) O(nlogn)→1436msO(nlogn)\to 1436msO(nlogn)→1436ms #inclu ...

  10. 【BZOJ 2119】 2119: 股市的预测 (后缀数组+分块+RMQ)

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 404  Solved: 188 Description 墨墨的妈妈热爱炒股,她 ...

随机推荐

  1. 01--STL泛型编程了解

    开始学习侯捷老师的课程了~~ 一:六大组件关系 容器(Container) 算法(Algorithm) 迭代器(Iterator) 仿函数(Function object) 适配器(Adaptor) ...

  2. SNMP支持IPv6

    SNMP Trap 网上好像很少提到ipv6的配置文件格式,这个配置文件的格式应该为:   trap2sink udp6:[fec0::]:: 创建监听的函数入口:netsnmp_udp_transp ...

  3. Hadoop记录-hadoop2.x常用端口及定义方法

    Hadoop集群的各部分一般都会使用到多个端口,有些是daemon之间进行交互之用,有些是用于RPC访问以及HTTP访问.而随着Hadoop周边组件的增多,完全记不住哪个端口对应哪个应用,特收集记录如 ...

  4. Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization(第一周)深度学习的实践层面 (Practical aspects of Deep Learning)

    1. Setting up your Machine Learning Application 1.1 训练,验证,测试集(Train / Dev / Test sets) 1.2 Bias/Vari ...

  5. 阿里Fastjson的使用

    Fastjson是一个Java语言编写的高性能功能完善的JSON库.由阿里巴巴公司团队开发的. 主要特性主要体现在以下几个方面: 1.高性能 fastjson采用独创的算法,将parse的速度提升到极 ...

  6. springboot(十八):解决跨域问题

    在controller上添加@CrossOrigin注解,如下: @RestController @RequestMapping("course") @CrossOrigin pu ...

  7. Retrofit的通讯方式示例

    Retrofit有两种通讯方式,同步和异步 异步方式: APIService req; req = RetrofitManager.getInstance().createReq(APIService ...

  8. bzoj 3620 暴力KMP

    十分暴力的KMP,枚举左端点,在向右侧推进的同时,取较小的la保证条件,n方暴力 #include<bits/stdc++.h> #define rep(i,j,k) for(int i= ...

  9. intptr_t 指针

    对于64为系统: typedef  signed char  int8_t; typedef short int int16_t; typedef int int32_t; # if __WORDSI ...

  10. 使用函数输出水仙花数 (void的用法)

    6-11 使用函数输出水仙花数 (20 分) 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身.例如:153=1​3​​+5​3​​+3​3​​. 本题要求编写两个函数, ...