【题目】#2303. 「NOI2017」蚯蚓排队

【题意】给定n条长度不超过6的蚯蚓,初始各自在一个队伍。m次操作:1.将i号蚯蚓和j号蚯蚓的队伍合并(保证i为队尾,j为队首)。2.将i号蚯蚓和它后面的蚯蚓分离成两个队。3.询问:给定字符串S和正整数k,求f(每个长度为k的子串)的乘积。其中f(S)定义为蚯蚓在其队伍向后延伸k位组成的字符串等于S的蚯蚓个数。\(n \leq 2*10^5,m \leq 5*10^5,k \leq 50,\sum |s| \leq 10^7,c \leq 10^3\),其中c为操作2的数量。

【算法】模拟+hash

【参考】LZZの知乎回答

暴力一点考虑,每个队伍维护一条链,合并和分裂时维护\(c_{x,i}\)表示第x号蚯蚓向后延伸i位的字符串hash值并更新长度为i的答案,查询的时候直接枚举子串访问长度为i的答案中hash值相同的。

容易知道这样最坏复杂度是\(O(mk^2+\sum |s|)\),理论上依然无法通过。

继续分析。

考虑分离操作至多c次,复杂度为\(O(ck^2)\)。

考虑合并操作,因为每次合并其实显然是不需要枚举满的,是否有可能省去一个k的复杂度?合并的终串中每个子串只会被统计一次(分离只有1000次,不影响复杂度),而总共有nk个子串,所以复杂度为\(O(nk)\)。

总复杂度\(O(ck^2+nk+\sum |s|)\)。

注意:我用的hash方式是一个小哈希存邻接表,一个大哈希当成真实值来检验。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
bool isdigit(char c){return c>='0'&&c<='9';}
int read(){
int s=0,t=1;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
do{s=s*10+c-'0';}while(isdigit(c=getchar()));
return s*t;
}
using namespace std;
const int maxn=200010,MOD=998244353,cmod=3000007,dmod=1000000007,basec=233,based=123,maxk=60,maxL=10000010;
int first[cmod+5],tot,n,m,a[maxL],b[maxL],E[maxk],f[maxk],A[maxn],c[maxn][maxk],d[maxn][maxk],nxt[maxn],pre[maxn];
char s[maxL];
struct edge{int k,v,x,from;}e[maxn*maxk];
void insert(int k,int u,int v,int x){
for(int i=first[u];i;i=e[i].from)if(e[i].k==k&&e[i].v==v){
e[i].x+=x;
return;
}
e[++tot]=(edge){k,v,x,first[u]};first[u]=tot;
}
int cM(int x){return x>=cmod?x-cmod:x;}
int dM(int x){return x>=dmod?x-dmod:x;}
int main(){
n=read();m=read();
E[0]=1;for(int i=1;i<=50;i++)E[i]=1ll*E[i-1]*basec%cmod;
f[0]=1;for(int i=1;i<=50;i++)f[i]=1ll*f[i-1]*based%dmod;
for(int i=1;i<=n;i++){
A[i]=read();
c[i][1]=d[i][1]=A[i];
insert(1,A[i],A[i],1);//
}
while(m--){
int kind=read();
if(kind==1){
int x=read(),y=read();
nxt[x]=y;pre[y]=x;
for(int i=1;i<50&&x;i++){
int z=y;
for(int j=1;i+j<=50&&z;j++){
c[x][i+j]=(1ll*c[x][i+j-1]*basec+A[z])%cmod;
d[x][i+j]=(1ll*d[x][i+j-1]*based+A[z])%dmod;
insert(i+j,c[x][i+j],d[x][i+j],1);
z=nxt[z];
}
x=pre[x];
}
}
else if(kind==2){
int x=read(),y=nxt[x];
nxt[x]=pre[y]=0;
for(int i=1;i<50&&x;i++){
int z=y;
for(int j=1;i+j<=50&&z;j++){
insert(i+j,c[x][i+j],d[x][i+j],-1);
z=nxt[z];
}
x=pre[x];
}
}
else{
scanf("%s",s+1);int len=strlen(s+1),k=read();
for(int i=1;i<=len;i++)a[i]=(1ll*a[i-1]*basec+s[i]-'0')%cmod;
for(int i=1;i<=len;i++)b[i]=(1ll*b[i-1]*based+s[i]-'0')%dmod;
int ans=1;
for(int i=1;i<=len-k+1;i++){
int x=cM(a[i+k-1]-1ll*a[i-1]*E[k]%cmod+cmod);
int y=dM(b[i+k-1]-1ll*b[i-1]*f[k]%dmod+dmod);
int num=0;
for(int j=first[x];j;j=e[j].from)if(e[j].v==y&&e[j].k==k){num=e[j].x;break;}
ans=1ll*ans*num%MOD;
}
printf("%d\n",ans);
}
}
return 0;
}

【NOI】2017 蚯蚓排队(BZOJ 4943,LOJ 2303) 模拟+hash的更多相关文章

  1. [NOI 2017]蚯蚓排队

    Description 题库链接 蚯蚓幼儿园有 \(n\) 只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从 \(1\) 到 \(n\) 的连续正整数编号.每只蚯蚓的长度 ...

  2. 【BZOJ4943】【NOI2017】蚯蚓排队(哈希)

    [BZOJ4943][NOI2017]蚯蚓排队(哈希) 题面 BZOJ 洛谷 UOJ 题解 记得去年看网络同步赛的时候是一脸懵逼的. 昨天看到\(zsy\)做了,今天就看了看.. 这不是\(Hash\ ...

  3. [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树

    [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树 题意 给定一个 \(n\) 个点边带权的无根树, 要求切断其中恰好 \(k\) 条边再连 \(k\) 条边权为 \(0\) ...

  4. [BZOJ 4031][LOJ 2122][HEOI 2015] 小Z的房间

    [BZOJ 4031][LOJ 2122][HEOI 2015] 小Z的房间 题意 给定一个 \(n\times m\) 的矩阵, 一些格子是障碍, 相邻的格子(四联通)之间可以连边, 求把非障碍的格 ...

  5. LOJ2303 「NOI2017」蚯蚓排队

    「NOI2017」蚯蚓排队 题目描述 蚯蚓幼儿园有$n$只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从$1$到$n$的连续正整数编号.每只蚯蚓的长度可以用一个正整数表示 ...

  6. NOI 2017滚粗退役记

    NOI 2017 游记 又到了OIer退役了的季节 Day -1 今天是报到日. 中午11点多的动车.动车上和dick32165401和runzhe2000谈笑风生.顺便用dick32165401的流 ...

  7. 「NOI2017」蚯蚓排队 解题报告

    「NOI2017」蚯蚓排队 这题真的草 你考虑\(k\)这么小,每次合并两个串,增加的有用串的数量是\(O(k^2)\)的,暴力加入这些串,求一下这些串的Hash值,塞到Hash表里面去 这里采用类似 ...

  8. NOI 2017 Day1 题解

    被虐爆了... T1 整数 题目传送门 Description 有一个整数 \(x\),有 \(n\) 此操作,每次操作为以下两种情况: 给出 \(a,b\),将 \(x\) 加上 \(a\times ...

  9. LOJ 2303 「NOI2017」蚯蚓排队——链表+哈希表

    题目:https://loj.ac/problem/2303 想到合并的时候可以只考虑接口附近的50个,但不太会分析复杂度,而且没有清楚地想到用哈希值对应个数. 看了题解才会…… 一直想用 splay ...

随机推荐

  1. unity2D以最小的角度旋转到目标方向(y方向为角色的主方向)

    一.使用向量原理转换到目标方向 为了让角色的自身y转向目标方向,并且以最小角度旋转,要点是获得当前方向与目标方向的叉值,从而判断应该旋转的方向 float rotateSpeed; //相对目标位置运 ...

  2. B1041. 考试座位号(15)

    这题比较简单,没有调试,一次通过,虽然简单,不过也有借鉴意义. #include<bits/stdc++.h> using namespace std; const int N=1005; ...

  3. zookeeper应用

    1. 下载zookeeper-3.4.10.tar.gz 2.tar zxvf zoo*.tar.gz 3. cd /usr/local/zookeeper/zookeeper-3.4.10/conf ...

  4. rethinking virtual network embedding..substrate support for path splitting and migration阅读笔记

    1.引言 网络虚拟化, 1.支持同一个底层网络有多种网络架构,每种架构定制一个应用或用户社区. 2.也可以让多个服务提供者在共同的物理基础设施上定制端到端的服务.如Voice over IP(VoIP ...

  5. 第二个Sprint计划

    第一个Sprint计划已完成基本框架,接着第二个计划 时间:5月30-6月3日 目标:能够将各个框架连接起来,实现基本功能,并查看数据库连接. 分工:杜殷浩:查看数据库连接,创建数据库. 何广强:实现 ...

  6. 组件 -- Alert

    alert的背景色: alert-primary alert-secondary alert-success . . . .alert : 警告框类 .data-dismiss = "ale ...

  7. nginx提示Job for nginx.service failed because the control的问题

    启动nginx时就报错!Job for nginx.service failed because the control process exited with error code. See &qu ...

  8. oralce下载

    oracle的官网网址:oracle.com 打开之后选择中文 然后在页面的下方找到下载和试用链接 点击进入,选择数据库下载,在页面中找到如下部分点击进入即可下载对应版本的oracle

  9. ubuntu关闭和开启防火墙

    1.关闭ubuntu的防火墙 ufw disable 2开启防火墙 ufw enable 3.卸载了iptables apt-get remove iptables 4.关闭ubuntu中的防火墙的其 ...

  10. 【题解】 Luogu P1541 乌龟棋总结 (动态规划)

    题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起 ...