NOI 2017 蚯蚓排队 题解
Problem
Meaning
给定一些数字,对它们进行首尾相接和断开两种操作。对于每次询问,求对于每个数字,其后长度一定的数字串在给定数字串中出现的次数,并给出这些次数之积。
Soultion
对于每次首尾相接或断开的操作,如果直接对断点或合点两侧的整个数字串进行操作,时间复杂度不可接受。由于每次查询只有向后 \(k\) 数字串会产生贡献,所以假设 \(k\) 一定,则只需要对断点或合点左侧 \(k-1\) 个数字进行操作。这道题的向后 \(k\) 数字串的长度极为有限,所以当断点或合点左侧最靠近断点或合点的数字是需要修改的数字的第 \(i\) 个后继时,我们即使在每次操作时对每一个需要修改的数字修改它的向后 \(i+2\) 到 \(50\)( \(k\) 的上界)数字串,也不会产生过大的时间开销。
在具体的操作过程中,我们可以取出以断点或合点为圆心,以 \(50\) 为半径的圆内的点,对断点或合点左侧的数字枚举向后数字串的长度记录这个数字串并累加它的出现次数即可。
为了方便取出这些圆上的点,我们可以使用链表对每个数字的前驱与后继进行记录,在对数字串进行操作的时候一并操作。
只需要取以断点或合点为圆心,以 $50$ 为半径的圆内的点的原因
当左侧一个数字的第 \(i-1\) 个后继在断点或合点右侧时这个数字的向后 \(i\) 数字串才会改变,所以左侧只需取 \(49\) 个点。
而即使是断点或合点左侧最靠近断点或合点的数字,也只需要最多 \(49\) 个右侧的数为它做出贡献,所以只需要取圆内的点,而不需要圆上与圆外的点。
由于在查询操作中需要求出数字串的子串,我们将所有对数字串的操作变为字符串操作。为了避免使用一些常数较大的 STL,考虑用数字代表每个字符串,将每个向后数字串哈希起来代表这个数字串,并使用哈希表记录每个数字串的出现次数,在查询操作时查询每个长度为 \(k\) 的子串的哈希值与对应出现次数并进行求积,即可得到答案。
Code
#include<bits/stdc++.h>
using namespace std;
const unsigned long long mdr=998244353,pp=33557999;
#define numhash(x) (x%pp)
unsigned long long n,m,a[200010],pre[200010],nxt[200010],t[200010];
struct node{
unsigned long long val;
unsigned long long hashv;
int next;
};
struct table{
node data[35000000];
int cnt,head[35000000];
inline unsigned long long& operator [] (unsigned long long x){
int temh=numhash(x);
for(int i=head[temh];i;i=data[i].next){
if(data[i].val==x) return data[i].hashv;
}
data[++cnt]={x,0,head[temh]};
head[temh]=cnt;
return data[cnt].hashv;
}
}mp,str;
int opt,o,p,pos;
string s;
int main(){
scanf("%llu%llu",&n,&m);
t[0]=1;
for(int i=1;i<=n;++i) t[i]=t[i-1]*11;
for(int i=1;i<=n;++i){
scanf("%llu",&a[i]);
++mp[a[i]];
}
for(;m>0;--m){
scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&o,&p);
int lft=49,rgt=50;
unsigned long long tem[150],hs[150];
for(int i=o;i&&lft;i=pre[i],--lft) tem[lft]=a[i];
++lft;
for(int i=p;i&&rgt<99;i=nxt[i],++rgt) tem[rgt]=a[i];
--rgt;
for(int i=lft;i<=rgt;++i) hs[i]=hs[i-1]*11+tem[i];
for(int i=lft;i<50;++i){
for(int len=51-i;len<=min(50,rgt-i+1);++len){
int j=i+len-1;
++mp[hs[j]-hs[i-1]*t[len]];
}
}
nxt[o]=p,pre[p]=o;
}else if(opt==2){
scanf("%d",&o);
p=nxt[o];
int lft=49,rgt=50;
unsigned long long hs[150],tem[150];
for(int i=o;i&&lft;i=pre[i],--lft) tem[lft]=a[i];
++lft;
for(int i=p;i&&rgt<99;i=nxt[i],++rgt) tem[rgt]=a[i];
--rgt;
for(int i=lft;i<=rgt;++i) hs[i]=hs[i-1]*11+tem[i];
for(int i=lft;i<50;++i){
for(int len=51-i;len<=min(50,rgt-i+1);++len){
int j=i+len-1;
--mp[hs[j]-hs[i-1]*t[len]];
}
}
nxt[o]=pre[p]=0;
}else{
cin>>s;
scanf("%d",&o);
int tem=s.length();
for(int i=0;i<tem;++i) str[i+1]=str[i]*11+s[i]-'0';
unsigned long long ans=mp[str[o]]%mdr;
for(int i=o+1;i<=tem;++i) ans=ans*mp[str[i]-str[i-o]*t[o]]%mdr;
printf("%llu\n",ans);
}
}
return 0;
}
NOI 2017 蚯蚓排队 题解的更多相关文章
- [NOI 2017]蚯蚓排队
Description 题库链接 蚯蚓幼儿园有 \(n\) 只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从 \(1\) 到 \(n\) 的连续正整数编号.每只蚯蚓的长度 ...
- 【NOI】2017 蚯蚓排队(BZOJ 4943,LOJ 2303) 模拟+hash
[题目]#2303. 「NOI2017」蚯蚓排队 [题意]给定n条长度不超过6的蚯蚓,初始各自在一个队伍.m次操作:1.将i号蚯蚓和j号蚯蚓的队伍合并(保证i为队尾,j为队首).2.将i号蚯蚓和它后面 ...
- BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4943 http://uoj.ac/problem/315 https://www.luogu.or ...
- NOI 2017 Day1 题解
被虐爆了... T1 整数 题目传送门 Description 有一个整数 \(x\),有 \(n\) 此操作,每次操作为以下两种情况: 给出 \(a,b\),将 \(x\) 加上 \(a\times ...
- 【BZOJ4943】【NOI2017】蚯蚓排队(哈希)
[BZOJ4943][NOI2017]蚯蚓排队(哈希) 题面 BZOJ 洛谷 UOJ 题解 记得去年看网络同步赛的时候是一脸懵逼的. 昨天看到\(zsy\)做了,今天就看了看.. 这不是\(Hash\ ...
- LOJ2303 「NOI2017」蚯蚓排队
「NOI2017」蚯蚓排队 题目描述 蚯蚓幼儿园有$n$只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从$1$到$n$的连续正整数编号.每只蚯蚓的长度可以用一个正整数表示 ...
- NOI 2017滚粗退役记
NOI 2017 游记 又到了OIer退役了的季节 Day -1 今天是报到日. 中午11点多的动车.动车上和dick32165401和runzhe2000谈笑风生.顺便用dick32165401的流 ...
- 「NOI2017」蚯蚓排队 解题报告
「NOI2017」蚯蚓排队 这题真的草 你考虑\(k\)这么小,每次合并两个串,增加的有用串的数量是\(O(k^2)\)的,暴力加入这些串,求一下这些串的Hash值,塞到Hash表里面去 这里采用类似 ...
- [NOI2017]蚯蚓排队 hash
题面:洛谷 题解: 我们暴力维护当前所有队伍内的所有子串(长度k = 1 ~ 50)的出现次数. 把每个子串都用一个hash值来表示,每次改变队伍形态都用双向链表维护,并暴力更新出现次数. 现在考虑复 ...
- World Finals 2017 (水题题解)
看大佬做2017-WF,我这种菜鸡,只能刷刷水题,勉强维持生活. 赛后补补水题. 题目pdf链接,中文的,tls翻译的,链接在这里 个人喜欢在vjudge上面刷题. E Need for Speed ...
随机推荐
- Zabbix Scheduled reports中文乱码
困扰了一天的问题,最后还是靠百度大神的方法解决.原文链接 https://blog.csdn.net/weixin_38587368/article/details/119357516 由于我的是容器 ...
- 字符串成员方法:截取、替换、切割 及String成员方法小结
1.截取 subString() subString()方法有两种使用方式: 1.第一种是在括号里只放入一个索引,这时将会从放入的索引为起点,一直截取到末尾 2.第二种是在括号里放入两个索引,分别对应 ...
- docker container 启动异常
场景重现 阿里云ECS下新安装的CoreOS 1465.8.0 64-bit,没做过其他任何操作,直接执行以下命令出现异常: docker pull hello-world docker run -i ...
- 什么是 MCP,以及你为什么该关注它
MCP 现在真的火起来了.现在已经有成千上万个 MCP "服务器",而且虽然是 Anthropic 发明的,就在几天前 OpenAI 也采纳了它.服务器就像 AI 的 " ...
- Semaphore.acquire()方法的底层原理
一.acquire() 的工作流程 当调用 acquire() 方法时,实际调用的是 AQS 的 acquireSharedInterruptibly(1) 方法.以下是其详细工作流程: // acq ...
- 阿里云服务器中Linux下centos7.6安装mysql8.0.11
1.下载安装 MySQL最新下载地址:https://dev.mysql.com/downloads/mysql/ 选择的是Linux 64位通用的二级制版本,这样不在需要进行编译安装,系统安装依赖 ...
- 【代码】Android|获取存储权限并创建、存储文件
版本:Android 11及以上,gradle 7.0以上,Android SDK > 29 获取存储权限 获取存储权限参考:Android 11 外部存储权限适配指南及方案,这篇文章直接翻到最 ...
- C#/.NET/.NET Core优秀项目和框架2025年4月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍.功能特点.使用方式以及部分功能 ...
- 鸿蒙开发中console.log和hilog的区别
在日常开发中打印日志是调试程序非常常用的操作,在鸿蒙的官方文档中介绍了hilog这种方式,有些前端转过来的友友发现console.log也可以进行日志打印.有一段时候幽蓝君也非常喜欢使用console ...
- k8s之ingress反向代理pod
Ingress controller Nginx -->后来改造 Traefik -->也是用于微服务 Envoy -->微服务 Ingress资源 目前使用0.17.1版本ing ...