YbtOJ-相似子串【SA,RMQ,二分】

1|0正题


1|1题目大意

给出一个长度为n的字符串,两个串相似当且仅当可以通过每种字符置换使得它们相同。

q次询问这个字符串所有子串中和这个串中sl,r子串有多少个相似的。

1n105,1q5×105

字符集是数字09


1|2解题思路

请问我是在阴间吗
请添加图片描述
首先对于相似的比较相信很常见,维护每个数字上一个和它相同的数字的距离,然后没有上一个就定为0就好了。

但是这题的问题在于我们提取出区间构成的数组时前面有些要变成0

同样的这也是个提示,因为字符集大小只有10,我们也可以从这里入手,对于一个后缀,我们把第一个出现的数字的位置挖空后,我们至多会把这个后缀以这些位置分成10份,我们将这个字符串序列称之为这个后缀的值。

然后我们需要的就是这些后缀值的“LCP”,而这样我们需要我们能快速求这些后缀中字符串的LCP。

子串的LCP直接上SA+RMQ就好了。

这样我们把弄出来的后缀的值排好序,然后维护一个相邻的两两之间的"LCP"计入一个类似height的数组的东西。

然后对于询问我们就直接二分在RMQ上查询就好了。

时间复杂度:O(10nlogn+qlogn)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=1e5+10; struct node{ int l,r; }; struct nstr{ vector<node> r; int id; }sr[N]; int n,m,q,nxt[10],p[10],pos[N]; int x[N],y[N],c[N],sa[N],rk[N]; int lg[N],f[N][20],h[N],s[N]; char rs[N]; void Qsort(){ for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++)c[x[i]]++; for(int i=1;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0; return; } void Get_SA(){ for(int i=1;i<=n;i++) x[i]=s[i]+1,m=max(m,s[i]+1),y[i]=i; Qsort(); for(int w=1;w<=n;w<<=1){ int p=0; for(int i=n-w+1;i<=n;i++)y[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>w)y[++p]=sa[i]-w; Qsort();swap(x,y);x[sa[1]]=p=1; for(int i=2;i<=n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+w]==y[sa[i-1]+w])?p:(++p); if(p==n)break;m=p; } return; } void Get_Height(){ int k=0; for(int i=1;i<=n;i++)rk[sa[i]]=i; for(int i=1;i<=n;i++){ if(rk[i]==1)continue; if(k)k--;int j=sa[rk[i]-1]; while(i+k<=n&&j+k<=n&&s[j+k]==s[i+k])k++; h[rk[i]]=f[rk[i]][0]=k; } return; } void Get_RMQ(){ for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); return; } int RMQ(int l,int r){ if(!l||!r)return 0; if(l==r)return n-l+1; l=rk[l];r=rk[r]; if(l>r)swap(l,r);l++; int z=lg[r-l+1]; return min(f[l][z],f[r-(1<<z)+1][z]); } int RMQs(int l,int r){ l++;int z=lg[r-l+1]; return min(f[l][z],f[r-(1<<z)+1][z]); } void SA(){ Get_SA(); Get_Height(); Get_RMQ(); return; } int cp(node x,node y){//x<=y if(!x.l&&!y.l)return 2; if(!x.l)return 1; if(!y.l)return 0; int len=RMQ(x.l,y.l); if(len>x.r-x.l||len>y.r-y.l){ if(x.r-x.l==y.r-y.l)return 2; return (x.r-x.l)<(y.r-y.l); } return s[x.l+len]<s[y.l+len]; } bool cmp(nstr x,nstr y){ int i=0; while(1){ if(i>=x.r.size())return 0; if(i>=y.r.size())return 1; int op=cp(x.r[i],y.r[i]); if(op==2)i++; else return op; } return 0; } int LCP(nstr x,nstr y){ int i=0,ans=0; while(i<x.r.size()&&i<y.r.size()&&cp(x.r[i],y.r[i])==2) ans+=x.r[i].r-x.r[i].l+1,i++; if(i<x.r.size()&&i<y.r.size())ans+=min(RMQ(x.r[i].l,y.r[i].l),min(x.r[i].r-x.r[i].l,y.r[i].r-y.r[i].l)+1); return ans; } int main() { // freopen("similar.in","r",stdin); // freopen("similar.out","w",stdout); scanf("%d%d",&n,&q); scanf("%s",rs+1); for(int i=1;i<=n;i++){ if(!nxt[rs[i]-'0'])s[i]=0; else s[i]=i-nxt[rs[i]-'0']; nxt[rs[i]-'0']=i; } SA();memset(nxt,0,sizeof(nxt)); for(int i=n;i>=1;i--){ nxt[rs[i]-'0']=i; for(int j=0;j<=9;j++)p[j]=nxt[j]; sort(p,p+10); int now=i; for(int j=0;j<=9;j++){ if(!p[j])continue; if(p[j]>now) sr[i].r.push_back((node){now,p[j]-1}); sr[i].r.push_back((node){0,0}); now=p[j]+1; } if(now<=n)sr[i].r.push_back((node){now,n}); sr[i].id=i; } sort(sr+1,sr+1+n,cmp); for(int i=1;i<=n;i++) pos[sr[i].id]=i; for(int i=2;i<=n;i++)h[i]=LCP(sr[i-1],sr[i]); for(int i=2;i<=n;i++)f[i][0]=h[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); int las=0; while(q--){ int l,r; scanf("%d%d",&l,&r); l^=las;r^=las; if(l>n||r>n||l<1||r<1)continue; int x=pos[l],len=r-l+1; int L=x+1,R=n,ans=1; while(L<=R){ int mid=(L+R)>>1; if(RMQs(x,mid)>=len)L=mid+1; else R=mid-1; } ans+=R-x;L=1;R=x-1; while(L<=R){ int mid=(L+R)>>1; if(RMQs(mid,x)>=len)R=mid-1; else L=mid+1; } ans+=x-L; printf("%d\n",las=ans); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15864835.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示