CF 427D 后缀数组
来源:互联网 发布:在windows上安装spark 编辑:程序博客网 时间:2024/05/16 12:24
题意:求两串字符串的公共最短子串,且这个子串只在任意一串中出现一次、
首先明确后缀数组将所有的后缀(也可以视为第i个点开始的子串)字典序排列,将最近似的子串集合在一起。
LCP求的是附近两个子串的最长公共前缀
如果某一个子串当且仅当出现两次,则必须是LCP[i]是局部最大。该子串最大长度为LCP[i],最短长度为max(lcp[i+1],lcp[i-1])+1;
同理,可以推出仅出现N次的子串(后缀自动机啦。)
#include <map>#include <set>#include <queue>#include <stack>#include <math.h>#include <vector>#include <cstdio>#include <string>#include<string.h>#include <fstream>#include <iostream>#include <algorithm>using namespace std;#define exp 1e-8#define INF 100000000#define ll long long#define set(a,b) memset(a,b,sizeof(a));#define for1(a,b,c) for(int a=1;a<=b;a+=c)//1---(b)#define for0(a,b,c) for(int a=0;a<b;a+=c)//0---(b-1)void bug(string st="bug"){cout<<st<<endl;}template<typename __ll>inline void READ(__ll &m){ __ll x=0,f=1;char ch=getchar(); while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m=x*f;}template<typename __ll>inline void read(__ll &m){READ(m);}template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}const int maxn=50000; //字符串总长度int scnt,k;//,k为被增发的kint rank[maxn];//第几位开始的后缀数组排第几位int sa[maxn];//对scnt个后缀数组排序后,第几位对应字符串的第几位//第一位为空字符串,即最后一位的‘\0’,在这个模板里,最后一位以‘\0’链接int lcp[maxn];//最长公共前缀,最终排好序的后缀子串i与子串i+1的最长公共前缀的长度int tmp[maxn];//协助更新bool cmp_sa(int i,int j){ if(rank[i]!=rank[j]) return rank[i]<rank[j]; int ri=i+k<=scnt?rank[i+k]:-1; int rj=j+k<=scnt?rank[j+k]:-1; return ri<rj;}void calc_sa(char *S)//计算字符串的后缀数组{ scnt=strlen(S); for(int i=0;i<=scnt;i++) //初始化 { sa[i]=i; rank[i]=i<scnt?S[i]:-1; //最后一位补上-1! } for(k=1;k<=scnt;k*=2)//!!注意此处是k=1,而不是int k=1;!!! { sort(sa,sa+scnt+1,cmp_sa); tmp[sa[0]]=0; for(int i=1;i<=scnt;i++) //int i=1; tmp[sa[i]]=tmp[sa[i-1]]+(cmp_sa(sa[i-1],sa[i])?1:0); for(int i=0;i<=scnt;i++) //int i=0; rank[i]=tmp[i]; }}void construct_lcp(char *S){ scnt=strlen(S); for(int i=0;i<=scnt;i++) rank[sa[i]]=i; int h=0; lcp[0]=0; for(int i=0;i<scnt;i++) { int j=sa[rank[i]-1]; if(h>0) h--; for(;j+h<scnt&&i+h<scnt;h++) if(S[j+h]!=S[i+h]) break; lcp[rank[i]-1]=h; }}//bool contain(char S[],char T[])//S为母串。检查T是否为子串void Union(char S[],char T[]){ int a=strlen(S); S[a]='$'; //此处以‘$’链接两个串 S[a+1]='\0'; strcat(S,T);}int main(){ char S[maxn],T[maxn]; scanf("%s",&S); int l=strlen(S); scanf("%s",&T); Union(S,T); int len=strlen(S); calc_sa(S); construct_lcp(S); int ans=100000000; for(int i=1;i<len;i++) if(lcp[i]>lcp[i-1]&&lcp[i]>lcp[i+1]&&((sa[i]<l)!=(sa[i+1]<l))) //求出符合的子串 ans=min(ans,max(lcp[i-1],lcp[i+1])+1); //更新最短的长度 if(ans==100000000) printf("-1\n"); else printf("%d\n",ans); return 0;}
0 0
- CF 427D 后缀数组
- cf 427D Match & Catch 后缀数组
- CF(427D-Match & Catch)后缀数组应用
- codeforces 427 D Match & Catch ( 后缀数组 )
- CodeForces 427D Match & Catch 后缀数组
- Codeforces 427D Match & Catch 后缀自动机 或 后缀数组
- hdu4436 && cf#244D 后缀自动机
- CF #244 (Div. 2) D Match & Catch (后缀数组 仅出现一次最短公共子串)
- CodeForces 427 D.Match & Catch(后缀数组)
- cf D. "Or" Game (前缀+后缀维护单点更新)
- CF 845D Jury Meeting 枚举断点+前缀后缀
- cf#381D 树状数组+二分
- codeforces 432D D . Prefixes and Suffixes(后缀数组)
- CF 12D BALL 线段树 && 树状数组
- CF 341D - Iahub and Xors(二维树状数组)
- CF 459D - Pashmak and Parmida's problem (树状数组)
- 【树状数组】CF 459D Pashmak and Parmida's problem
- cf 459D Pashmak and Parmida's problem 树状数组
- 从枚举类型的ordinal()方法说起
- Java方法中引用类型的形参传递问题
- 0325笔试(未完)
- Log4cplus使用
- 怎样在github上协同开发
- CF 427D 后缀数组
- WordNet词网研究7——之JWS(Java Wordnet Similarity)语义相似度计算
- jrtplib—VS2010下RTP开源协议库JRTPLIB3.9.1编译
- 领悟
- paste.deploy程序示例
- iPhone 6 / 6 Plus 设计·适配方案
- Java Socket 编程指南
- 中缀表达式转换为后缀表达式
- linux下的程序分析工具——gprof