dtoj3198 字符串(string)
令 与 为两字符串,定义:
1. 表示字符串 在区间 中的子串;
2. 在 中出现的频率定义为 在 中出现的次数;
3. 表示 在 中出现的频率。
比如 。
现在给定串 , 个区间 和长度 ,你要回答 个询问,每个询问给你一个长度为 的字符串 和两个整数 ,求:
Sol
对S串建出sam,预处理每个节点right集合大小。
注意到Q*k=1e5 考虑分类讨论:、
1.Q>k
枚举Q,枚举w的每一个子串[l,r],二分出询问[l,r]中有多少个在[a,b]中,乘上right大小即可。
效率O(q*k^2*log)=O(wsqrt(w)log)
2.Q<k
枚举Q,枚举w的每一位,记录在sam上匹配到了哪个点,匹配长度是多少。
然后枚举a到b的每一个区间[l,r],先走到r,然后倍增到l,加上right即可
效率O(Q(k+m))

#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<queue> #define maxn 400005 using namespace std; int n,li,len,ls,cnt,ans[maxn],tr[maxn][94],fail[maxn],head[maxn],tot; int dfn[maxn],ed[maxn],sc,c[maxn]; char ch[maxn],s[maxn]; struct no{ int v,nex; }e[maxn]; void add(int t1,int t2){ e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot; } struct bit{ int tr[maxn]; void add(int i,int v){ for(;i<=cnt;i+=i&-i)tr[i]+=v; } int ask(int i){ int sum=0;for(;i;i-=i&-i)sum+=tr[i];return sum; } }T; struct node{int p,id;}; vector<node>q[maxn]; vector<int>G[maxn]; void ins(int l,int id){ for(int i=1;i<=l;i++)ch[i]-=33; int k=0; for(int i=1;i<=l;i++){ if(!tr[k][ch[i]])tr[k][ch[i]]=++cnt; k=tr[k][ch[i]]; } k=0; for(int i=l;i>0;i--){ if(!tr[k][ch[i]])tr[k][ch[i]]=++cnt; k=tr[k][ch[i]];ed[i]=k; } k=0; q[0].push_back((node){ed[li+1],id}); cout<<ed[2]<<' '<<ed[li+1]<<' '<<id<<endl; for(int i=1;i+li<=l;i++){ k=tr[k][ch[i]]; if(i+li==l)q[k].push_back((node){-1,id}); else q[k].push_back(node{ed[i+li+1],id}); } } void build(){ queue<int>q; for(int i=0;i<94;i++)if(tr[0][i])q.push(tr[0][i]); while(!q.empty()){ int k=q.front();q.pop(); add(fail[k],k); for(int i=0;i<94;i++){ if(tr[k][i])fail[tr[k][i]]=tr[fail[k]][i],q.push(tr[k][i]); else tr[k][i]=tr[fail[k]][i]; } } } void dfs(int k){ dfn[k]=++sc; for(int i=head[k];i;i=e[i].nex)dfs(e[i].v); ed[k]=sc; } void solve(int k){ for(int i=head[k];i;i=e[i].nex)solve(e[i].v); for(int i=0;i<G[k].size();i++){ T.add(G[k][i],1); } for(int i=0;i<q[k].size();i++){ node t=q[k][i]; if(t.id==1)cout<<k<<' '<<t.p<<' '<<G[k].size()<<endl; if(t.p==-1)ans[t.id]+=T.ask(ed[0]); else ans[t.id]+=T.ask(ed[t.p])-T.ask(dfn[t.p]-1); } for(int i=0;i<G[k].size();i++)T.add(G[k][i],-1); } int main(){ cin>>li;scanf(" %s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++)s[i]-=33; cin>>n; for(int i=1;i<=n;i++){ scanf("%s",ch+1); int l=strlen(ch+1); if(l<=li)ans[i]=n-l+1; else ins(l,i); } build();dfs(0); cout<<"haha "<<tr[0]['z'-33]<<endl; int k=0;c[n+1]=dfn[0]; for(int i=n;i>=1;i--){ k=tr[k][s[i]];c[i]=k; } k=0;G[0].push_back(li); for(int i=1;i+li<=n;i++){ k=tr[k][s[i]]; cout<<k<<' '<<fail[k]<<' '<<c[i+li+1]<<endl; G[k].push_back(c[i+li+1]); } solve(0); for(int i=1;i<=n;i++)printf("%d\n",ans[i]); return 0; }
分类:
字符串
, 字符串---后缀自动机
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构