首页 > 其他分享 >MCE学习笔记

MCE学习笔记

时间:2024-04-06 23:35:47浏览次数:17  
标签:同构 MCE 位置 最小 笔记 学习 开头 字符串

MCE 学习笔记

最小表示法。

你说的对,月考考完了,但是感觉基本炸了。/ll/ll,相对失败。

艹,写了我一个晚上。

\(\frac{3}{20}\),还差的远呢。

闲话:MCE 是 a3 叫的,不过感觉挺好听。

这个算法出题的话可能就比较板了,所以不是很热门?

不废话了。

引入定义:

  • 循环同构,对于两个字符串 \(S\) 和 \(T\),如果可以在 \(T\) 中找到一个位置,使得从这个位置开始在这个字符串绕一圈(就把这个字符串看成环),使得他和 \(S\) 相等,那么说明 \(S\) 和 \(T\) 是循环同构的。

  • 定义字符串 \(S\) 中从 \(l\) 为起点,\(r\) 为终点的字符顺次连接组成的字符串为 \(S(l,r)\)。

容易发现,能和 \(S\) 构成循环同构的字符串,一定是从 \(S\) 任意一个位置开头,转一圈得到的字符串。(根据定义,\(T\) 复原成 \(S\) 的过程,反过来就是 \(S\) 断开组成 \(T\) 的过程。)

所以,完全可以通过复制两次 \(S\),找到所有和 \(S\) 循环同构的字符串。

最小表示法解决的问题就是,对于 \(S\) 所有与其循环同构的字符串中,找到字典序最小的。

因为这样的字符串只有 \(n\) 个,所以显然有 \(O(n^2)\) 的做法。

但是这个东西,可以 \(O(n)\)。

首先有两个下标 \(i,j\),考虑我们正在比较以 \(i\) 为开头和以 \(j\) 为开头的两个循环同构哪个更优,当前比较了前 \(k\) 位都是一样的。

先提醒一下,对于 \(i\) 这个位置,(包含 \(i\))往后第 \(k\) 个位置是 \(S_{i+k-1}\)。

分类讨论。

  • 如果 \(k+1\) 也相同,那么 k++ 即可。
  • 如果不同,假设 \(S_{i+k}<S_{j+k}\),可以发现,以 \(i\) 开头的更优,同时,从 \([j,j+k]\) 所有位置的,都不优。,\(j\) 直接跳到 \(j+k+1\) 即可。

原因显然,如果以 \(i+1\) 和 \(j+1\) 开头比较的话,(就相当于\(S(i,i+k)\)和 \(S(j,j+k)\) 删掉一位。) 到第 \(k+1\) 位 以 \(j+1\) 开头的不优,依此类推,到第 \(k+1\) 位,都是不优的。

时间复杂度证明:可以发现,\(i\) 和 \(j\) 都不会走回头路,类似双指针。那么一个位置最多会被踩两次,时间复杂度为 \(O(n)\)。

讲讲代码,代码比较高妙。

int MCE(){
	for(int i=1;i<=n;i++)	c[i]=c[i+n]=a[i];
	int i=1,j=2;
	while(i<=n&&j<=n){
		int k=1;
		while(k<=n&&c[i+k-1]==c[j+k-1])	k++;
		if(k>n)	break;
		if(c[j+k-1]>c[i+k-1])	j=j+k;
		else	i=i+k;
		if(i==j)	j++;
	}
	return min(i,j);
}

思考两个问题:

  • 最后 return min(i,j) 的原因?如果 \(i\)(或者 \(j\))是劣的且 \(i\) 跳到 \(i+k\) 后大于 \(n\),跳出循环,这时候原先的 \(i\) 是劣的那个,不能取,且一定大于 \(j\)。(或者说,此时的 \(i\) 根本就没存任何一个位置的答案。)

  • if(k>n) break; 原因? 这个很厉害。这要满足,如果一个字符串 \(S=T+T+...+T\) 的话,(\(T\) 长度最小。)\(i\) 恰好是 \(T\) 中字典序最小的位置(这个可以反证,如果不是最小的话,在匹配就不能构成连续 \(n\) 个均可以匹配。就是不满足 \(k>n\))。

这个时候 \(j\) 就又恰好移动到了 \(i+m\) 的位置,(这个也可以反证,不然不满足 \(T\) 是长度最小的,证出来发现 \(T=S(i,j-1)\) 才是最小的,和假设矛盾。用UVA10298来理解,就是把 \(S(i,i+n-1)\) 和 \(S(j,j+n-1)\) 上下来看,一直上下拼推一推就行。)进而和从 \(i\) 开始往后的 \(n\) 个字符,都是一样的了,所以 \(i\) 就是最优的。

注意细节,if(i==j) j++,一定要这一步,不然匹配了两个相同位置开头的字符串就一定执行 if(k>n) break,求出来就不是正确答案了。

没有什么习题。

CF496B

标签:同构,MCE,位置,最小,笔记,学习,开头,字符串
From: https://www.cnblogs.com/JuneFailue/p/18118177

相关文章

  • SCC学习笔记
    SCC学习笔记好听点的话来说,就是强连通分量。一个有向图,里面任意两个节点之间可以相互到达,我们把它称为一个强连通分量。Kosaraju首先,对于一个强连通的图,显然,他的反图也是一个强连通图。(因为原先\(A\)可以到\(B\),\(B\)可以到\(A\),反过来是一样的)做法是从任意一个点开始,......
  • 生成树学习笔记
    最小生成树学习笔记代码合集很好,这还是一篇复习笔记。考虑这么一个问题,给出一张无向图,有\(n\)个点,\(m\)条边,边有边权,要你找\(n-1\)条边,使得这\(n\)个点联通且边权和最小。Kruskal首先,我们先把边权进行排序,然后贪心的加边,把选的边所带的点加到一个集合里面。如果\(x......
  • 单调栈 and 单调队列学习笔记
    单调栈and单调队列学习笔记本文均以维护单调递增的栈/队列举例。本篇代码合集以后在写动态规划单调队列/单调栈优化的时候,这两个东西会合并。单调栈本质上就是模拟。假设要维护一个单调递增的栈,那么对于一个元素进来了,在栈顶的所有比他小的数我全部都要踢出去,不然就不满足......
  • 并查集学习笔记
    并查集学习笔记本质上还是一个复习笔记。考虑这样一个问题:给出\(x,y\),合并\(x,y\)所在集合。给出\(x,y\),查询\(x,y\)是否在同一集合内。我们把集合当成一棵树,两个点有连边就表示他们在同一个集合内。这棵树的根节点就是这个集合的“老大”,也就是这个集合里面的......
  • Docker学习笔记(三)Dockerfile指令详解
    文章目录FROM指定基础镜像RUN执行命令COPY复制文件ADD高级文件复制CMD容器启动命令ENTRYPOINT入口点ENV设置环境变量ARG构建参数VOLUME定义匿名卷EXPOSE声明端口WORKDIR指定工作目录USER指定当前用户HEALTHCHECK健康检查ONBUILD构建触发器LABEL添加元数据......
  • C语言学习笔记--(2)基础语法
    我先写点,我不太擅长写,所以各位有问题可以评论说,我看到一定改一.C语言编程的格式    我们可以先看一个关于C语言的基础实例下面是一个简单的C语言程序,用于计算购买商品的总价,并根据折扣计算最终支付金额。#include<stdio.h>//计算购买商品的总价floatcalculat......
  • 后端学习记录~~JavaSE篇(day03-流程控制语句-上)
    if...else与Switch...case语句一、表达式和语句表达式:(1)变量或常量+运算符构成的计算表达式(2)new表达式,结果是一个数组或类的对象。(3)方法调用表达式,结果是方法返回值或void(无返回值)。语句:(1)分支语句:if...else,switch...case(2)循环语句:for,while,do...while(3)跳转语句:brea......
  • React 学习之 Hello World
    React学习之HelloWorldReact简介React是一个用于构建用户界面的JavaScript库,由Facebook开发并维护。React通过声明式的方式来构建UI,使得代码更易于理解和测试。React的核心概念包括组件(Component)和虚拟DOM(VirtualDOM)。组件:在React中,UI被构建为组件的集合。组件是封装了HTM......
  • 2-SAT 学习笔记
    2-SAT学习笔记P4782【模板】2-SAT2-SAT问题模型:构造bool变量\(x_1,x_2...x_n\),使得满足一些限制一对\(x_1\)和\(x_2\)取值的条件合法。很显然根据Floyd传递闭包可以做到\(O(n^3+m)\),但不太行。有\(O(n+m)\)的做法,发现对于每个条件是要我们选择一种取值(选择就很......
  • [笔记]数位dp例题及详解(更新中)
    数位dp的定义引自洛谷日报#84:求出在给定区间\([L,R]\)内,符合条件\(f(i)\)的数\(i\)的个数。条件\(f(i)\)一般与数的大小无关,而与数的组成有关。由于是按位dp,数的大小对复杂度的影响很小。由于数位dp状态的上下文信息比较多,所以一般用记忆化搜索实现,而非递推。P4999烦人的数......