dtoj2099. 字符串查询( find)
给定n个字符串和q个询问
每次询问在这n个字符串中,有多少个字符串同时满足
1. 字符串a是它的前缀
2. 字符串b是它的后缀
内存128M
Sol
这题我想了个log的做法可是它卡空间!!
可以建两个AC自动机,然后相当于给你一个点的映射,每次询问两颗子树内相同的点有几个。
那么在一个树上线段树合并,另一个区间查询就是nlog的
那么这一题我们只好先把字符串排序,然后二分出a的可行区间,b的可行区间。
离线完a树状数组维护就行。
效率nlog2

#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #define ll unsigned long long #define p 793999 #define maxn 50005 using namespace std; int n,Q; int tr[maxn],dy[maxn],ans[maxn]; void add(int i,int v){ for(;i<=n;i+=i&-i)tr[i]+=v; } int ask(int i){ int sum=0;for(;i;i-=i&-i)sum+=tr[i];return sum; } struct node{ int id,len; char ch[105]; ll h[105]; void R(){ scanf("%s",ch+1);len=strlen(ch+1); for(int j=1;j<=len;j++)h[j]=h[j-1]*p+ch[j]; } void re(){ for(int i=1,j=len;i<j;i++,j--)swap(ch[i],ch[j]); for(int j=1;j<=len;j++)h[j]=h[j-1]*p+ch[j]; } }s[maxn],S[maxn],a,b; struct que{ int id,op,l,r; }; vector<que>q[maxn]; bool operator ==(node A,node B){ if(A.len!=B.len)return 0; return A.h[A.len]==B.h[B.len]; } int find(node A,node B){ int M=min(A.len,B.len); if(A.ch[1]!=B.ch[1])return 0; int l=1,r=M; while(l<r){ int mid=(l+r+1)>>1; if(A.h[mid]==B.h[mid])l=mid; else r=mid-1; } return l; } bool operator <(node A,node B){ int x=find(A,B); if(min(A.len,B.len)==x)return A.len<B.len; return A.ch[x+1]<B.ch[x+1]; } bool cmp(node a,node b){ return a<b; } int get(int l,node t){ int r=n; while(l<r){ int mid=l+r+1>>1; if(find(s[mid],t)==t.len)l=mid; else r=mid-1; } return l; } int Get(int l,node t){ int r=n; while(l<r){ int mid=l+r+1>>1; if(find(S[mid],t)==t.len)l=mid; else r=mid-1; } return l; } int main(){ cin>>n>>Q; for(int i=1;i<=n;i++)s[i].R(); sort(s+1,s+n+1,cmp); for(int i=1;i<=n;i++){ s[i].id=i; S[i]=s[i];S[i].re(); } sort(S+1,S+n+1,cmp); for(int i=1;i<=n;i++)dy[S[i].id]=i; for(int i=1;i<=Q;i++){ a.R();b.R();b.re(); int l=lower_bound(s+1,s+n+1,a)-s,r=get(l,a); int L=lower_bound(S+1,S+n+1,b)-S,R=Get(L,b); if(l>n||L>n)continue; if(find(s[l],a)!=a.len)continue; if(find(S[L],b)!=b.len)continue; q[l-1].push_back((que){i,-1,L,R}); q[r].push_back((que){i,1,L,R}); } for(int i=1;i<=n;i++){ add(dy[i],1); for(int j=0;j<q[i].size();j++){ que t=q[i][j]; ans[t.id]+=t.op*(ask(t.r)-ask(t.l-1)); } } for(int i=1;i<=Q;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语句:使用策略模式优化代码结构