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 蚯蚓排队 题解的更多相关文章

  1. [NOI 2017]蚯蚓排队

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

  2. 【NOI】2017 蚯蚓排队(BZOJ 4943,LOJ 2303) 模拟+hash

    [题目]#2303. 「NOI2017」蚯蚓排队 [题意]给定n条长度不超过6的蚯蚓,初始各自在一个队伍.m次操作:1.将i号蚯蚓和j号蚯蚓的队伍合并(保证i为队尾,j为队首).2.将i号蚯蚓和它后面 ...

  3. BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4943 http://uoj.ac/problem/315 https://www.luogu.or ...

  4. NOI 2017 Day1 题解

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

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

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

  6. LOJ2303 「NOI2017」蚯蚓排队

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

  7. NOI 2017滚粗退役记

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

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

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

  9. [NOI2017]蚯蚓排队 hash

    题面:洛谷 题解: 我们暴力维护当前所有队伍内的所有子串(长度k = 1 ~ 50)的出现次数. 把每个子串都用一个hash值来表示,每次改变队伍形态都用双向链表维护,并暴力更新出现次数. 现在考虑复 ...

  10. World Finals 2017 (水题题解)

    看大佬做2017-WF,我这种菜鸡,只能刷刷水题,勉强维持生活. 赛后补补水题. 题目pdf链接,中文的,tls翻译的,链接在这里 个人喜欢在vjudge上面刷题. E Need for Speed ...

随机推荐

  1. linux命令提示符高亮

    说明 \033 或 \e :两者是等价的,表示转义字符(ASCII escape character),即键盘左上角的ESC键.033是ESC的八进制ASCII码.注意,在"老式" ...

  2. PHP 读取csv中的指定某些列的值

    封装一个方法,用于从CSV文件中读取指定的某些列的值时,可以使用以下示例代码: <?php class CSVReader { private $filename; private $delim ...

  3. 新装的 MySQL 不允许远程连接

    新装的 MySQL 通常会出现这样的情况:无法远程连接,但是本地连接是正常的. 问题原因 新装的 MySQL 通常默认的用户是 root, 而为了安全起见, root 用户是不允许远程连接. mysq ...

  4. Tomcat知识点整理

    从学习起就开始接触tomcat, 解压, 点击运行, 然后放文件夹里面会自动部署, 可以通过ip访问. 在这里主要记录一些tomcat相关的知识点 配置文件解析(留位置) server.xml/web ...

  5. App自动化环境部署

    1.所需工具 Android-SDK:自行百度下载 Appium-Desktop:自行百度下载 真机或模拟器:自行准备 2.部署步骤 1)配置Android-SDK 解压Android-SDK压缩包 ...

  6. leetcode001 两数之和

    问题描述:两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答 ...

  7. should contain指令的用法,校验结果

    上图案例 商品添加后,匹配"商品名称","现价","库存" 首先获取"商品名称","现价",&quo ...

  8. Innodb快速复习

    放一张官方架构图: 参考文章: 一文带你了解MySQL之InnoDB_Buffer_Pool-阿里云开发者社区这一篇buffer pool讲解的很好 [动画演示:MySQL的BufferPool和Ch ...

  9. 国产的 Java Solon v3.2.0 发布(央企信创的优选)

    Solon 框架! Solon 是新一代,Java 企业级应用开发框架.从零开始构建(No Java-EE),有灵活的接口规范与开放生态.采用商用友好的 Apache 2.0 开源协议,是" ...

  10. SpringBoot事件驱动开发

    应用启动过程生命周期事件感知(9大事件).应用运行中事件感知(无数种) 事件发布:ApplicationEventPublisherAware或注入:ApplicationEventMulticast ...