[BZOJ4698][Sdoi2008]Sandy的卡片(后缀数组+st表||后缀自动机)
来源:互联网 发布:网络虚拟手机号发短信 编辑:程序博客网 时间:2024/05/20 12:52
题目描述
传送门
题目大意:给出n个长度为mi的串,求趋势相同的最长公共子串
题解
将前后两个数差分之后就是一个裸的最长公共子串问题了
将所有的串怼在一起求sa和height,然后用一个指针扫出来至少含有n个串的最短区间,然后用st表求区间min就行了
好久不写sa各种傻逼,比如说st表求max而不是求min啦,,,还有先枚举i再枚举j啦…
同时这道题也是一道sam的裸题,求多个串的最长公共子串
对第一个串建sam,然后其它的串在上面匹配,对每一个点每一次求Max,总体求Min,然后在Min中选一个max
连map都不用
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 200005#define sz 18#define base 2000int cnt,n,m,ans;int s[N],*x,*y,X[N],Y[N],c[N],sa[N],height[N],rank[N];int st[N][sz+3],lg[N],tot[N],id[N],ed[N];void build_sa(){ m=4000; x=X,y=Y; for (int i=0;i<n;++i) ++c[x[i]=s[i]]; for (int i=1;i<m;++i) c[i]+=c[i-1]; for (int i=n-1;i>=0;--i) sa[--c[x[i]]]=i; for (int k=1;k<=n;k<<=1) { int p=0; for (int i=n-k;i<n;++i) y[p++]=i; for (int i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k; for (int i=0;i<m;++i) c[i]=0; for (int i=0;i<n;++i) ++c[x[y[i]]]; for (int i=1;i<m;++i) c[i]+=c[i-1]; for (int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for (int i=1;i<n;++i) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&(sa[i-1]+k<n?y[sa[i-1]+k]:-1)==(sa[i]+k<n?y[sa[i]+k]:-1)?p-1:p++; if (p>=n) break; m=p; }}void build_height(){ for (int i=0;i<n;++i) rank[sa[i]]=i; int k=0; for (int i=0;i<n;++i) { if (!rank[i]) continue; int j=sa[rank[i]-1]; if (k) --k; while (s[i+k]==s[j+k]&&i+k<n&&j+k<n) ++k; height[rank[i]]=k; }}void rmq(){ for (int i=1,p=0;i<=n;++i) { while ((1<<p)<=i) ++p; lg[i]=p-1; } for (int i=0;i<n;++i) st[i+1][0]=height[i]; for (int j=1;j<sz;++j) for (int i=1;i<=n;++i) if (i+(1<<j)-1<=n) st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);}int query(int l,int r){ l+=2,++r; if (l>r) return 0; int k=lg[r-l+1]; return min(st[l][k],st[r-(1<<k)+1][k]);}int main(){ scanf("%d",&cnt); for (int i=1;i<=cnt;++i) { int m,x,y;scanf("%d%d",&m,&x); for (int j=1;j<m;++j) { scanf("%d",&y); s[n++]=y-x+base;id[n-1]=i; x=y; } s[n++]=0;id[n-1]=i; ed[i]=n-1; } build_sa(); build_height(); for (int i=1;i<n;++i) height[i]=min(height[i],min(ed[id[sa[i-1]]]-sa[i-1],ed[id[sa[i]]]-sa[i])); rmq(); int pt=0,now=0; while (!s[sa[now]]) ++now,++pt; ++tot[id[sa[pt]]]; int sum=1; while (now<n) { while (pt<n&&tot[id[sa[pt]]]-1) { --tot[id[sa[pt]]]; ++pt; } if (sum==cnt) ans=max(ans,query(pt,now)); ++now; if (!tot[id[sa[now]]]) ++sum; ++tot[id[sa[now]]]; } printf("%d\n",ans+1);}
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 205#define base 2000int cnt,n,root,last,sz,p,np,q,nq,ans;int s[N],ch[N][4005],pre[N],step[N],Max[N],Min[N],pt[N],c[N];void extend(){ root=last=++sz; for (int i=0;i<n;++i) { int x=s[i]; p=last;np=++sz;last=np; step[np]=step[p]+1; while (p&&!ch[p][x]) { ch[p][x]=np; p=pre[p]; } if (!p) pre[np]=root; else { q=ch[p][x]; if (step[q]==step[p]+1) pre[np]=q; else { nq=++sz; step[nq]=step[p]+1; pre[nq]=pre[q]; memcpy(ch[nq],ch[q],sizeof(ch[q])); while (ch[p][x]==q) { ch[p][x]=nq; p=pre[p]; } pre[np]=pre[q]=nq; } } }}void sam(){ memset(Max,0,sizeof(Max)); int p=root,len=0; for (int i=0;i<n;++i) { int x=s[i]; if (ch[p][x]) p=ch[p][x],++len; else { while (p&&!ch[p][x]) p=pre[p]; if (!p) p=root,len=0; else len=step[p]+1,p=ch[p][x]; } Max[p]=max(Max[p],len); } for (int i=sz;i>=1;--i) { p=pt[i]; if (Max[p]) Max[pre[p]]=step[pre[p]]; } for (int i=1;i<=sz;++i) Min[i]=min(Min[i],Max[i]);}int main(){ scanf("%d",&cnt); memset(Min,127,sizeof(Min)); for (int i=1;i<=cnt;++i) { int m,x,y;scanf("%d%d",&m,&x); n=0; for (int j=1;j<m;++j) { scanf("%d",&y); s[n++]=y-x+base; x=y; } if (i==1) { extend(); for (int i=1;i<=sz;++i) ++c[step[i]]; for (int i=2;i<=sz;++i) c[i]+=c[i-1]; for (int i=sz;i>=1;--i) pt[c[step[i]]--]=i; } else sam(); } for (int i=1;i<=sz;++i) ans=max(ans,Min[i]); printf("%d\n",ans+1);}
0 0
- [BZOJ4698][Sdoi2008]Sandy的卡片(后缀数组+st表||后缀自动机)
- 后缀自动机 【Sdoi2008】 Sandy的卡片 bzoj4698
- bzoj4698 [Sdoi2008] Sandy的卡片(后缀数组+二分答案)
- bzoj 4698: Sdoi2008 Sandy的卡片 (后缀数组+二分)
- BZOJ4698 Sdoi2008 Sandy的卡片
- Bzoj4698: [Sdoi2008]Sandy的卡片
- bzoj4698 Sdoi2008 Sandy的卡片
- [bzoj4698][SDOI2008]Sandy的卡片
- bzoj 4698 Sandy的卡片 后缀数组
- bzoj4698Sdoi2008 Sandy的卡片 后缀数组+二分
- 【SDOI2008】Sandy的卡片 DP
- BZOJ 4698 Sdoi2008 Sandy的卡片
- BZOJ 4698: Sdoi2008 Sandy的卡片
- 【后缀自动机】自动机<->后缀树<->后缀数组
- 后缀自动机 转变为 后缀数组
- [BZOJ2119]股市的预测(后缀数组+st)
- [BZOJ3277]串(后缀数组+二分+st表)
- [BZOJ3230]相似子串(后缀数组+二分+st表)
- 自定义View_绘制圆_进行拖动(不出屏幕)放大缩小
- setTimeout机制的思考
- 区间DP
- Cesium应用篇:3控件(5)CesiumInspector
- Java 泛型
- [BZOJ4698][Sdoi2008]Sandy的卡片(后缀数组+st表||后缀自动机)
- 关于HIS客户端程序登陆后提示“the oracle library OCI.DLL could not be loaded”
- 用 CSS 实现三角形与平行四边形
- Wu Xing
- 源码分析mycat1.6之mysql通信协议篇之COM_QUERY(SELECT语句报文解析)
- bram和dram区别
- Cesium应用篇:3控件(4)Geocoder
- 如何在PHP中使用Oracle数据库(6)
- Sudoku HDU