cf Educational Codeforces Round 134 E. Prefix Function Queries

news2024/11/17 20:37:54

原题:
You are given a string s, consisting of lowercase Latin letters.

You are asked q queries about it: given another string t, consisting of lowercase Latin letters, perform the following steps:

concatenate s and t;
calculate the prefix function of the resulting string s+t;
print the values of the prefix function on positions |s|+1,|s|+2,…,|s|+|t| (|s| and |t| denote the lengths of strings s and t, respectively);
revert the string back to s.
The prefix function of a string a is a sequence p1,p2,…,p|a|, where pi is the maximum value of k such that k<i and a[1…k]=a[i−k+1…i] (a[l…r] denotes a contiguous substring of a string a from a position l to a position r, inclusive). In other words, it’s the longest proper prefix of the string a[1…i] that is equal to its suffix of the same length.

Input
The first line contains a non-empty string s (1≤|s|≤10^6), consisting of lowercase Latin letters.

The second line contains a single integer q (1≤q≤10^5) — the number of queries.

Each of the next q lines contains a query: a non-empty string t (1≤|t|≤10), consisting of lowercase Latin letters.

Output
For each query, print the values of the prefix function of a string s+t on positions |s|+1,|s|+2,…,|s|+|t|.

Examples
input
aba
6
caba
aba
bababa
aaaa
b
forces
output
0 1 2 3
1 2 3
2 3 4 5 6 7
1 1 1 1
2
0 0 0 0 0 0
input
aacba
4
aaca
cbbb
aab
ccaca
output
2 2 3 1
0 0 0 0
2 2 0
0 0 1 0 1

中文:
给你个字符串s,然后给你q个不同的字符串t。每次构造一个新的字符串s+t,记|s|为字符串s长度,|t|为字符串t的长度,现在要每次计算出|s| + 1到 |s| + |t|的next值(就是kmp的next数组)

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
string s, t;
int jump[maxn][26];
int Next[maxn];
int q;
void solve()
{
	cin>>s;
	int n=s.size();
	s=' '+s;
	for (int i=1,j=0;i<=n;i++)
	{
		if (i!=1) {
			while (j&&s[j+1]!=s[i]) {
                j=Next[j];
			}
			if (s[j+1]==s[i]) {
                j++;
			}
			Next[i] = j;
		}
		for (int k=0;k<26;k++) {
			if (i!=n&&s[i+1]==char('a'+k)) {
                jump[i][k]=i;
			}
			else {
                jump[i][k]=jump[Next[i]][k];
			}
		}
	}
	/*
	cout << "next val = " << endl;
    for (int i = 1; i <= n; i++) {
        cout << Next[i] << " ";
    }
    cout << endl;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 26; j++) {
            if (jump[i][j] == 0) {
                continue;
            }
            cout << "jump[" << i <<"][" << char(j+'a') <<"] = " << jump[i][j] << endl;
        }
        cout << endl;
    }
    cout << endl;
    */
    cin>>q;
	while (q--)
	{
		cin>>t;
		int m=t.size();
		int j=Next[n];
		s+=t;
		for (int i=n+1,j=Next[n];i<=n+m;i++) {
			while (j&&s[j+1]!=s[i]) {
				if (j<=n) {
				    // cout << "j = " << j << " dp = " << jump[j][st[i] - 'a'] <<" " << (st[j+1] == st[i]) << endl;
					j=jump[j][s[i]-'a'];
					break;
				}
				j=Next[j];
			}
			if (s[j+1]==s[i]) {
                j++;
			}
			Next[i] = j;
			cout<<Next[i]<<" ";
		}
		cout<<endl;
		while (m--) {
            s.pop_back();
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int t=1;
	while (t--) {
		solve();
	}
	return 0;
}

思路:

肯定能想到是kmp算法,因为要计算前缀数组,如果暴力求解会超时,这里需要使用kmp自动机,如果有ac自动机的基础,则很容易想到。
考虑如下字符串
s = “ababcabaa”
t = "baba
那么s+t = “ababcabaababa”
计算出字符串s的前缀数组为:

1  2  3  4  5  6  7  8  9 | 
------------------------- |
a  b  a  b  c  a  b  a  a | b  a  b  a
0  0  1  2  0  1  2  3  1 |  

如果使用原始kmp算法直接计算新拼接的字符串部分的next值会超时。
这里需要使用kmp自动机的概念,以上面的字符串为例
在这里插入图片描述
如上图,前缀abab与原始字符串最后一个字符串与新添加的后缀可以完全匹配上,但是到了前缀第5个字符串与后缀第5个字符分别是’c’和’a’不匹配。这时观察原始字符串前缀中abab这个子串,如果与其匹配的字符串的下一个字符串是c,那么当前的状态就应该返回4,即
jump [“abab”][‘c’] = 4,即得到"abab"最后一个一个’b’的位置。如果是遇到其它字符,则需要根据next数组,找到可以匹配的最长前缀的位置,比如jump[“abab”][‘a’] = ? ,由于next[“abab”] = 2,表示子串“abab"的前缀和后缀可以匹配上两个,即”ab",正巧前缀的“ab"下一个字符是’a’,那么jump[“abab”][‘a’] = 2,即表示如果"abab"匹配上了,下一个字符遇到的不是c,而是a的情况下,可以向前查找到的可匹配状态为2。
有了上面的jump数组,在计算新添加的字符串数组的时候,就可以利用jump信息,在新添加的字符与前缀字符未匹配上的时候,应该与前缀的某一个子状态可以匹配上。

ps:此题目也可以使用离线方法完成,将所有查询的字符串搜集起来并排序,找到公共前缀再进行计算,这样可以明显减少匹配次数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/174367.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实战打靶集锦-001-Funbox2

**写在前面&#xff1a;**这应该是本人第一次自主成功完成的打靶&#xff0c;纪念一下下。 目录1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 Apache探查4.1.1 浏览器访问4.1.2 站点地图查看4.1.3 目录枚举4.1.4 公共EXP搜索4.2 FTP探查4.2.1 手工登录FTP4.2.2 公共EXP搜索…

基于决策树模型和支持向量机模型的手写数字识别

目录 1、导入库和手写数字数据集 2、 把数据可视化 3、把数据分成训练数据集和测试数据集 4、训练SVM模型 5、训练决策树模型 6、对所使用的模型进行评估 7、对手写数字图像进行预测 本项目实现了 第一个功能&#xff1a;可以通过导入库和数据集、通过对数据集的预处理…

JavaScript基础(17)_Function方法(call、apply)、arguments

概念 call&#xff0c;apply都属于Function.prototype的一个方法&#xff0c;它是JavaScript引擎内在实现的&#xff0c;因为属于Function.prototype&#xff0c;所以每个Function对象实例(就是每个方法)都有call&#xff0c;apply属性&#xff0c;可以通过函数对象来调用。 a…

2023牛客寒假算法基础集训营3 赛时思路+正解

这场数学和思维偏多&#xff0c;特别是数学&#xff0c;五个小时过于充实了&#xff0c;而且更加考验你的心态。 这场不乏码量大的毒瘤题&#xff0c;也不乏人类智慧妙妙题。 A 不断减损的时间 题意 给定一个数组aaa&#xff0c;我们可以执行任意次操作&#xff0c;该操作定义…

Rethinking Performance Gains in Image Dehazing Networks

论文源码&#xff1a;https://download.csdn.net/download/zhouaho2010/87393184 Abstract 图像去雾是低层视觉中的一个活跃话题&#xff0c;随着深度学习的快速发展&#xff0c;许多图像去雾网络被提出。尽管这些网络的工作良好&#xff0c;但提高图像去雾性能的关键机制仍不…

守望者的逃离

题目说明【问题描述】恶魔猎手尤迫安野心勃勃.他背叛了暗夜精灵&#xff0c;率深藏在海底的那加企图叛变&#xff1a;守望者在与尤迪安的交锋中遭遇了围杀.被困在一个荒芜的大岛上。为了杀死守望者&#xff0c;尤迪安开始对这个荒岛施咒&#xff0c;这座岛很快就会沉下去&#…

【java入门系列五】java基础-面向对象**

学习记录&#x1f914;类与对象内存中的布局堆栈成员方法 类内的函数传参机制传进来的是一个数组/对象&#xff0c;类似于py的list调用递归-在栈空间方法递归汉诺塔八皇后方法重载overload可变参数作用域**scope构造器/构造方法&#xff1a;新对象的初始化构造器细节对象创建流…

pytorch 笔记:torch.nn.init

这个模块中的所有函数都是用来初始化神经网络参数的&#xff0c;所以它们都在torch.no_grad()模式下运行&#xff0c;不会被autograd所考虑。 1 计算gain value 1.1 介绍 这个在后面的一些nn.init初始化中会用到 1.2 用法 torch.nn.init.calculate_gain(nonlinearity, para…

【LeetCode】回溯算法总结

回溯法解决的问题 回溯法模板 返回值&#xff1a;一般为void参数&#xff1a;先写逻辑&#xff0c;用到啥参数&#xff0c;再填啥参数终止条件&#xff1a;到达叶子节点&#xff0c;保存当前结果&#xff0c;返回遍历过程&#xff1a;回溯法一般在集合中递归搜索&#xff0c;集…

使用DiskGenius进行硬盘数据迁移

克隆硬盘 - DiskGenius 1.迁移磁盘 选择自己想要迁移的磁盘&#xff0c;点击工具-克隆磁盘 首先选择源硬盘&#xff0c;点击确定 之后选择想要迁移到的硬盘&#xff0c;点击确定 检查一下原硬盘和目标硬盘是否正确&#xff0c;此外还可以对这个空间进行二次调整。最终如果没有…

Android 中关于 FileObserver类监听文件状态的实践

文章目录需求背景走进源码实现示例参考需求背景 当某一个目录的文件发生变化&#xff08;创建、修改、删除、移动&#xff09;时&#xff0c;需要给一个回调事件给其他端调用。 其他场景&#xff1a;阅后即焚等等。 比如在 Android 的 VR 设备中&#xff0c;有一个用于部署的文…

Oracle P6 Professional专业版 22.12 中的热门新功能

目录 并排查看项目 在复制与 WBS 元素的关系时具有更大的灵活性 更轻松地确定要分配的正确基线 复制并粘贴电子表格中的单元格区域 更好地控制导入数据 检查 P6 专业版中提供的时间表报告 在排序对话框中排列字段顺序 创建导入和导出模板的副本 指定完成日期筛选器如何…

光流估计(一) 光流的简介与操作

今天是大年29&#xff0c;明天要贴春联了&#xff01;算是在年前赶出来一篇文章发&#xff08;太长时间没发东西了O。o&#xff09;&#xff0c;也算是自己在光流估计深度学习部分研究的开始~ 明年开学就是研二下学期了&#xff0c;时间过得飞快&#xff0c;毕设、实习、工作等…

MyBatis | 使用插件better-mybatis-generator自动生成dao、pojo

0️⃣简介&#x1f5fc;简介在我们编写MyBatis的项目时&#xff0c;常常需要为数据表编写大量的SQL语句以及dao类。better-mybatis-generator作为一款IDEA插件&#xff0c;可以自动为我们生成所需要的pojo类、dao类&#xff0c;并提供相当多的SQL单表查询操作。利用该插件&…

Python小技巧:富比较方法的妙用,__lt__、__le__、__eq__、__ne__、__gt__、__ge__。。。

前言 这里是Python小技巧的系列文章。这是第二篇&#xff0c;富比较方法的妙用。 在 Python中&#xff0c;富比较方法共6个&#xff0c;如下表所示&#xff1a; 见名知意&#xff0c;富比较主要用于比较。 富比较方法使用释义释义object.__lt__(self, other)x.__lt__(y)x<…

Springboot+mybatis使用PageHelper实现vue前端分页

Springbootmybatis使用PageHelper实现vue前端分页1、未分页前的vue前端效果图2、Springbootmybatis使用PageHelper分页逻辑&#xff1a;&#xff08;1&#xff09;Springboot、mybatis、PageHelper的版本&#xff1a;&#xff08;2&#xff09;yml文件配置pagehelper&#xff1…

带你了解docker是什么----初始篇

docker容器docker简介docker、虚拟环境与虚拟机docker 的核心概念Docker 镜像Docker 仓库Docker容器镜像、容器、仓库&#xff0c;三者之间的联系容器 容器一词的英文是container&#xff0c;其实container还有集装箱的意思&#xff0c;集装箱绝对是商业史上了不起的一项发明&…

11.3 关联容器操作

文章目录关联容器迭代器关键字成员不可修改&#xff0c;值可修改关于泛型算法添加元素向set插入元素向map插入数据insert操作总结检测insert的返回值展开递增语句向multiset和multimap添加元素删除元素map下标操作访问元素类型别名&#xff1a;类型别名说明key_type关键字类型&…

第一个Spring、第一个SpringBoot、Spring-Mybatis整合、SpringBoot-Mybatis整合

目录一、第一个Spring程序二、第一个SpringBoot三、Spring-Mybatis整合四、SpringBoot-Mybatis整合第一个程序一、第一个Spring程序 添加依赖——用以支持spring <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</a…

线程池的简单介绍以及实现一个线程池

文章目录1、线程池存在的意义2、什么是线程池&#xff1f;3、线程池的使用2、java标准库中的线程池3、认识一下不同的线程池&#xff1a;4、认识一下线程池里的参数&#xff1a;4、实现一个简单的线程池1、线程池存在的意义 线程存在的意义&#xff1a;使用进程来实现并发编程…