bzoj 4556 [Tjoi2016&Heoi2016]字符串
来源:互联网 发布:mac怎么播放wmv 编辑:程序博客网 时间:2024/06/11 12:18
4556: [Tjoi2016&Heoi2016]字符串
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 952 Solved: 374
[Submit][Status][Discuss]
Description
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?
Input
输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来
m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,
字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n
Output
对于每一次询问,输出答案。
Sample Input
5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4
Sample Output
1
1
2
2
2
HINT
Source
【分析】
看阿当学长的代码肝还肝了两个多小时
我们发现这道鬼畜的题用LCP不好搞,于是翻转一下,变成了求LCS蛤蛤。
把串翻转以后建出来一只后缀自动机,搞出来pre树。
我们惊奇的发现如果区间[a,b]中某个节点和d的节点在pre树上的LCA的深度为dep,那么dep可以来更新答案。
显然不能枚举[a,b]区间里每一个数,那么我们二分答案。
发现其实[c,d]串如果考虑LCS的话c没有什么卵用,只是用来卡答案上界的。设当前答案为
总复杂度
我一直在想一个问题,为什么Markdown里面的代码片这么丑呢。
【代码】
//bzoj 4556 字符串 #include<bits/stdc++.h>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int M=4000005;const int mxn=200005;char s[mxn];int ls[M],rs[M];int m,T,len,tot,p,q,np,nq,size;int b[mxn],C[mxn],root[mxn],pos[mxn],step[mxn],son[mxn][28],pre[mxn][22];inline void insert(int &x,int l,int r,int v){ x=(++size); int mid=l+r>>1; if(l==r) return; if(v<=mid) insert(ls[x],l,mid,v); else insert(rs[x],mid+1,r,v);}inline int merge(int x,int y){ if(!x) return y; if(!y) return x; int z=(++size); ls[z]=merge(ls[x],ls[y]); rs[z]=merge(rs[x],rs[y]); return z;}inline bool find(int x,int l,int r,int L,int R){ if(!x) return 0; if(l==L && r==R) return 1; int mid=l+r>>1; if(R<=mid) return find(ls[x],l,mid,L,R); else if(L>mid) return find(rs[x],mid+1,r,L,R); else return find(ls[x],l,mid,L,mid)||find(rs[x],mid+1,r,mid+1,R);}inline void sam(){ int i,j,c; np=tot=1; fo(i,1,len) { c=s[i]-'a'+1,p=np; step[np=(++tot)]=step[p]+1; pos[i]=np,insert(root[np],1,len,i); while(p && !son[p][c]) son[p][c]=np,p=pre[p][0]; if(!p) {pre[np][0]=1;continue;} q=son[p][c]; if(step[q]==step[p]+1) pre[np][0]=q; else { step[nq=(++tot)]=step[p]+1; memcpy(son[nq],son[q],sizeof son[q]); pre[nq][0]=pre[q][0]; pre[q][0]=pre[np][0]=nq; while(p && son[p][c]==q) son[p][c]=nq,p=pre[p][0]; } } fo(i,1,tot) b[step[i]]++; fo(i,1,tot) b[i]+=b[i-1]; fo(i,1,tot) C[b[step[i]]--]=i; for(i=tot;i>=1;i--) { int x=C[i],fa=pre[x][0]; root[fa]=merge(root[fa],root[x]); } fo(j,1,20) fo(i,1,tot) pre[i][j]=pre[pre[i][j-1]][j-1];}inline bool check(int mid,int x,int l,int r){ for(int i=20;i>=0;i--) if(step[pre[x][i]]>=mid) x=pre[x][i]; return find(root[x],1,len,l,r);}int main(){ int i,j,a,b,c,d; scanf("%d%d",&len,&m); scanf("%s",s+1); reverse(s+1,s+len+1); sam(); while(m--) { scanf("%d%d%d%d",&a,&b,&c,&d); a=len-a+1,b=len-b+1,c=len-c+1,d=len-d+1; swap(a,b),swap(c,d); int l=0,r=min(d-c+1,b-a+1); while(l<r) { int mid=(l+r>>1)+1; if(check(mid,pos[d],a+mid-1,b)) l=mid; else r=mid-1; } printf("%d\n",l); } return 0;}
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串
- bzoj 4556 [Tjoi2016&Heoi2016]字符串
- bzoj 4556 [Tjoi2016&Heoi2016]字符串
- bzoj 4556 [Tjoi2016&Heoi2016]字符串
- 4556: [Tjoi2016&Heoi2016]字符串
- 4556: [Tjoi2016&Heoi2016]字符串
- 4556: [Tjoi2016&Heoi2016]字符串
- [后缀数组 主席树] BZOJ 4556 [Tjoi2016&Heoi2016]字符串
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串 后缀数组 主席树
- [达成成就:Tjoi2016&Heoi2016全AC] bzoj 4556: [Tjoi2016&Heoi2016]字符串 后缀数组+可持久化线段树
- 4556: [Tjoi2016&Heoi2016]字符串 后缀自动机 详细
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- Bzoj4556: [Tjoi2016&Heoi2016]字符串
- BZOJ4556 [Tjoi2016&Heoi2016]字符串
- bzoj4556【TJOI2016&HEOI2016】字符串
- BZOJ4556: [Tjoi2016&Heoi2016]字符串
- [Tjoi2016&Heoi2016]字符串
- JZOJ4614. 【TJOI2016&HEOI2016】字符串
- Websocket 个人总结
- 欢迎使用CSDN-markdown编辑器
- 虚拟内存
- CKplayer与video标签实用于ios和Android的示例
- 再eclipse查看某个java类属于哪个jar包
- bzoj 4556 [Tjoi2016&Heoi2016]字符串
- 大神一步步教你读懂ORB算法,赞!!
- Android 利用kenBurnsView实现启动页
- 拓展js中String对象的方法
- 高质量的子程序1
- 【加密解密】ADFGX密码 --图形界面实现加密解密
- ATX 文档
- 课程连接
- vue 2.0 父组件调用子组件中的方法