[NOI2017] 蚯蚓排队
XLI.[NOI2017] 蚯蚓排队
算算数据范围,可以哈希,只需要将所有长度在 以内的串扔进哈希表,然后询问时找到对应的串的出现次数即可。
这里的哈希表必须用双哈希,其中第一维开在数组范围内,然后第二维作为链表挂在后面,因此范围可以无限大。不过因为要在 int
内处理,因此我两个模数分别取了 4999999
和 299999977
,底数是 11
和 7
,这样就在 int
内了。
维护蚯蚓排队的过程可以手写链表。
比较悲催的一点是,为了卡空间,我写了链表中回收废弃节点的操作,但是却忘记用了,然后空间还开的是卡过后的大小,最后很是debug一会才找出来。
时间复杂度 。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[200100],pv1[60],pv2[60];
const int mod1=4999999,mod2=299999977,bs1=11,bs2=7,mod=998244353;
struct HashTable{
int head[mod1],nxt[200100],val[200100],num[200100],cnt,bin[200100],tp;
HashTable(){memset(head,-1,sizeof(head));}
int newnode(){return tp?bin[tp--]:cnt++;}
void ins(int x,int y,int d){
for(int *i=&head[x];*i!=-1;i=&nxt[*i]){
if(val[*i]!=y)continue;
num[*i]+=d;if(!num[*i])bin[++tp]=*i,*i=nxt[*i];return;
}
int id=newnode();
nxt[id]=head[x],val[id]=y,num[id]=d,head[x]=id;
}
int ask(int x,int y){for(int i=head[x];i!=-1;i=nxt[i])if(val[i]==y)return num[i];return 0;}
}ht[50];
struct List{
int las,nex;
List(){las=nex=-1;}
}l[200100];
int S,K;
char s[10001000];
void merge(){
int x,y;
scanf("%d%d",&x,&y);
l[x].nex=y,l[y].las=x;
for(int i=1;x!=-1&&i<50;x=l[x].las,i++){
int p=0,q=0;
for(int j=x,k=0;j!=-1&&k<50;j=l[j].nex,k++){
p=(bs1*p+a[j])%mod1;
q=(bs2*q+a[j])%mod2;
if(k>=i)ht[k].ins(p,q,1);
}
}
}
void split(){
int t,x,y;scanf("%d",&t),x=t,y=l[x].nex;
for(int i=1;x!=-1&&i<50;x=l[x].las,i++){
int p=0,q=0;
for(int j=x,k=0;j!=-1&&k<50;j=l[j].nex,k++){
p=(bs1*p+a[j])%mod1;
q=(bs2*q+a[j])%mod2;
if(k>=i)ht[k].ins(p,q,-1);
}
}
l[t].nex=l[y].las=-1;
}
int query(){
scanf("%s%d",s,&K),S=strlen(s);
int p=0,q=0,res=1;
for(int i=0;i<S;i++){
if(i>=K)(p+=mod1-pv1[K-1]*(s[i-K]-'0')%mod1)%=mod1,(q+=mod2-pv2[K-1]*(s[i-K]-'0')%mod2)%=mod2;
// printf("%d %d\n",p,q);
p=(p*bs1+(s[i]-'0'))%mod1,q=(q*bs2+(s[i]-'0'))%mod2;
if(i>=K-1)res=1ll*res*ht[K-1].ask(p,q)%mod;
if(!res)return 0;
}
return res;
}
int main(){
pv1[0]=pv2[0]=1;for(int i=1;i<50;i++)pv1[i]=pv1[i-1]*bs1%mod1,pv2[i]=pv2[i-1]*bs2%mod2;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),ht[0].ins(a[i],a[i],1);
int qt=0;
for(int i=1,tp;i<=m;i++){
scanf("%d",&tp);
if(tp==1)merge();
if(tp==2)split();
if(tp==3)printf("%d\n",query());
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?