COJ975 WZJ的数据结构(负二十五)
2015-07-05 10:10
537 查看
试题描述
输入一个字符串S,回答Q次问题,给你l,r,输出子序列[l,r]的最长连续回文串长度。
输入
第一行为一个字符串S。
第二行为一个正整数Q。
接下来Q行每行为l,r。
输出
对于每个询问,输出答案。
输入示例
aababababaabababaaa
4
1 3
2 6
1 10
2 7
输出示例
2
5
9
5
其他说明
1<=|S|,Q<=100000
1<=l<=r<=|S|
由于求区间的最长回文串长度,这显然不是很容易的事情,我们考虑用分块来维护答案。
我们每SIZE个元素分成一块,询问时要得到大块之间的答案以及小部分贡献的答案。
前者我们可以预处理出来(马拉车或PAM),时间复杂度O(N^2/SIZE)。
后者我们可以用PAM,当回文串的一段在小段时,肯定是左端在左小段,右端在右小段。两者是对称的,我们开始考虑怎么求回文串右端在右小段的答案。
预处理每个位置在PAM上的节点,但这可能超过询问边界,所以我们要不停地沿失配边向上走,当节点的的长度<=限制长度时返回。
如果暴力的话虽然对于随机数据表现很好,但会被特殊数据卡。因此我们可以用倍增来做,那么这一部分的时间复杂度为O(Q*SIZE*logSIZE)。
总时间复杂度为O(N^2/SIZE+Q*SIZE*logSIZE),实测SIZE取[150,200]即可。
View Code
输入一个字符串S,回答Q次问题,给你l,r,输出子序列[l,r]的最长连续回文串长度。
输入
第一行为一个字符串S。
第二行为一个正整数Q。
接下来Q行每行为l,r。
输出
对于每个询问,输出答案。
输入示例
aababababaabababaaa
4
1 3
2 6
1 10
2 7
输出示例
2
5
9
5
其他说明
1<=|S|,Q<=100000
1<=l<=r<=|S|
由于求区间的最长回文串长度,这显然不是很容易的事情,我们考虑用分块来维护答案。
我们每SIZE个元素分成一块,询问时要得到大块之间的答案以及小部分贡献的答案。
前者我们可以预处理出来(马拉车或PAM),时间复杂度O(N^2/SIZE)。
后者我们可以用PAM,当回文串的一段在小段时,肯定是左端在左小段,右端在右小段。两者是对称的,我们开始考虑怎么求回文串右端在右小段的答案。
预处理每个位置在PAM上的节点,但这可能超过询问边界,所以我们要不停地沿失配边向上走,当节点的的长度<=限制长度时返回。
如果暴力的话虽然对于随机数据表现很好,但会被特殊数据卡。因此我们可以用倍增来做,那么这一部分的时间复杂度为O(Q*SIZE*logSIZE)。
总时间复杂度为O(N^2/SIZE+Q*SIZE*logSIZE),实测SIZE取[150,200]即可。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<stack> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define ren for(int i=first[x];i;i=next[i]) using namespace std; 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; } const int maxn=100010; char ch[maxn]; int lpos[maxn],rpos[maxn],nowret; struct PAM { int last,cnt,to[maxn][26],l[maxn],fa[maxn]; int first[maxn],next[maxn],To[maxn],anc[maxn][20],e; void init() { memset(to,0,sizeof(to)); memset(l,0,sizeof(l)); memset(fa,0,sizeof(fa)); memset(first,0,sizeof(first)); cnt=fa[0]=1;l[1]=-1;last=e=0; } void extend(int c,int n,int id) { int p=last; while(ch !=ch[n-l[p]-1]) p=fa[p]; if(!to[p][c]) { int np=++cnt,k=fa[p];l[np]=l[p]+2; while(ch !=ch[n-l[k]-1]) k=fa[k]; fa[np]=to[k][c];to[p][c]=np; } nowret=max(nowret,l[last=to[p][c]]); if(id>0) lpos[id]=last; else rpos[-id]=last; } stack<int> S; void dfs(int x) { S.push(x); while(!S.empty()) { x=S.top();S.pop(); anc[x][0]=fa[x]; rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1]; ren S.push(To[i]); } } void AddEdge(int u,int v) { To[++e]=v;next[e]=first[u];first[u]=e; } void build() { fa[1]=1;rep(i,0,cnt) if(i!=1) AddEdge(fa[i],i); dfs(1); } int solve(int x,int limit) { if(l[x]<=limit) return l[x]; for(int i=19;i>=0;i--) if(l[anc[x][i]]>limit) x=anc[x][i]; return l[fa[x]]; } }sol1,sol2; int n,SIZE; int ans[750][750],bl[maxn],st[maxn],en[maxn]; int main() { scanf("%s",ch+1);n=strlen(ch+1);SIZE=150; rep(i,1,n) { bl[i]=(i-1)/SIZE+1; en[bl[i]]=i; if(!st[bl[i]]) st[bl[i]]=i; } rep(i,1,bl ) { sol1.init();nowret=0; char c=ch[st[i]-1];ch[st[i]-1]='~'; rep(j,st[i],n) { sol1.extend(ch[j]-'a',j,1); ans[i][bl[j]]=max(ans[i][bl[j]],nowret); } ch[st[i]-1]=c; } sol1.init();sol2.init(); rep(i,1,n) sol1.extend(ch[i]-'a',i,i); reverse(ch+1,ch+n+1); rep(i,1,n) sol2.extend(ch[i]-'a',i,-(n-i+1)); sol1.build();sol2.build(); int m=read(); while(m--) { int l=read(),r=read(),ret=0; if(bl[l]+1>=bl[r]) rep(i,l,r) ret=max(ret,sol1.solve(lpos[i],i-l+1)); else { ret=ans[bl[l]+1][bl[r]-1]; rep(i,l,en[bl[l]]) ret=max(ret,sol2.solve(rpos[i],r-i+1)); rep(i,st[bl[r]],r) ret=max(ret,sol1.solve(lpos[i],i-l+1)); } printf("%d\n",ret); } return 0; }
View Code
相关文章推荐
- 数据结构--队列
- 数据结构——关于二叉树
- PAT《数据结构学习与实验指导》实验项目集 2-06
- 算法与数据结构八日谈之四——树论
- 数据结构
- 重踏学习Java路上_Day17(登录注册案例,Set集合,Collection集合总结,在集合中常见的数据结构)
- 【可持久化】可持久化数据结构学习笔记
- 我的学习计划---第一部分数据结构与算法
- 数据结构和算法-011 数组排序 快速排序
- 数据结构基础温故-2.栈
- 数据结构—基础知识
- 【数据结构】利用栈来求算术表达式的值
- redis基础数据结构和数据对象
- 重温《大话数据结构》笔记一 单链表链式存储结构的操作代码
- malloc 结合内部数据结构讲解逻辑实现原理
- MySQL索引背后的数据结构及算法原理
- libeven入门数据结构bufferevent
- COJ976 WZJ的数据结构(负二十四)
- 数据结构习题之树
- COJ977 WZJ的数据结构(负二十三)