热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

OI养老专题02:约瑟夫问题求幸存者

如题。人数为n(1<n<30000),共k(1<k<30000)组数据,所报的数m恒为2,只要求输出幸存者。如果你还不知道什么是约瑟夫问题——ht

  如题。人数为n(1<=n<=30000),共k(1<=k<=30000)组数据,所报的数m恒为2,只要求输出幸存者。


  如果你还不知道什么是约瑟夫问题...——https://www.cnblogs.com/akura/p/10758080.html

  如果直接暴力枚举,那么时间复杂度就为O(NM)=O(N),所有数据一共O(KNM)=O(KN)。遇上这道题就爆掉了。

  那么怎么解决这种大数据的题呢?我们先手玩一把n个人的约瑟夫问题。由于每次对于n取模后的值在[0,n-1]之间,所以我们干脆让所有人的编号减1,也就是:0,1,2,......n-1。并且假设他们也从0~n-1报数。那么第一轮报数之后,出局的人就是:m%n-1。设tn=m%n,那么去掉了编号为tn-1的人之后,得到的序列就为:tn,tn+1......n-2,n-1,0,1,2......tn-2(tn-1出局了,所以没有),而他们报的数依次为0,1,2......n-1。不难发现,两个序列每个对应的元素相差为tn

  现在我们再手玩一把人数为n-1的约瑟夫问题。第一轮报数后,出局的人就是m%(n-1)-1。类似地,设tn-1=m%(n-1),剩下的序列就为:tn-1,tn-1+1......n-3,n-2,0,1,2......tn-1-2,他们报的数依次为0,1,2......n-2。两个序列每个对应的元素相差为tn-1。那么我们脑补一下递归的过程,最后我们会递归到边界:人数为1的情况。此时的幸存者就是0(编号减了1)。所以我们可以考虑通过人数少的来推出人数多的。设人数为n-1时的幸存者为ans,通过刚才的推导,不难发现当人数为n时幸存者就是(ans+m%n)%n。所以我们可以根据人数为1时幸存者为0递推上去,时间复杂度为O(N)。

  由于本题有很多组数据,而我们又得出了递推公式,我们可以离线处理,用f(i)表示当人数为i时幸存者的编号,则f(i)=(f(i-1)+m)%n,每次询问时回答即可,时间复杂度为O(N+K)。或者......在线处理也是没问题的,只要加上神奇的倍增。下面再深入介绍一下倍增的做法。

  不难发现,当n非常大,而m又小得可怜(比如本题)时,ans每次增加m之后对n取模还是等于ans+m,也就是说ans只增加了m。如果还是一次一次地加m的话,后面对n取模的语句始终是用不到的。所以不妨加快这个过程?设ans+m*x=n+x+1,也就是说ans最多增加x次之后仍然小于n,即对n取模的语句无用。至于为什么n要加x,是因为往上递推了x次之后,人数也会增加x(注意我们是从人少的情况往上递推!)。分离参数之后得x<(n-ans)/(m-1),x>=(n-ans)/(m-1)-1,可得x=floor((n-ans)/(m-1))。所以我们每次累加上x*m即可,并把循环的参数i调高x。不过要注意一些细节:

  1.当ans+m>n时直接上递推式子即可。

  2.当i+x>=n时就累加不到x次了,只能加n-i+1次。

  在线倍增的时间复杂度为O( ∑(1,n) ceil( i/ floor( i/m ) ) )≈O( ceil( n2/ floor( n2/m ) ) ),所以,复杂度接近O(M)?那么所有数据一共O(KM)。在线算法的尊严!可惜只在本题这种m=2的情况下可能跑得过离线。


推荐阅读
  • 使用Numpy实现无外部库依赖的双线性插值图像缩放
    本文介绍如何仅使用Numpy库,通过双线性插值方法实现图像的高效缩放,避免了对OpenCV等图像处理库的依赖。文中详细解释了算法原理,并提供了完整的代码示例。 ... [详细]
  • Vue 2 中解决页面刷新和按钮跳转导致导航栏样式失效的问题
    本文介绍了如何通过配置路由的 meta 字段,确保 Vue 2 项目中的导航栏在页面刷新或内部按钮跳转时,始终保持正确的 active 样式。具体实现方法包括设置路由的 meta 属性,并在 HTML 模板中动态绑定类名。 ... [详细]
  • 本文详细介绍了 BERT 模型中 Transformer 的 Attention 机制,包括其原理、实现代码以及在自然语言处理中的应用。通过结合多个权威资源,帮助读者全面理解这一关键技术。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • QBlog开源博客系统:Page_Load生命周期与参数传递优化(第四部分)
    本教程将深入探讨QBlog开源博客系统的Page_Load生命周期,并介绍一种简洁的参数传递重构方法。通过视频演示和详细讲解,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文探讨了如何像程序员一样思考,强调了将复杂问题分解为更小模块的重要性,并讨论了如何通过妥善管理和复用已有代码来提高编程效率。 ... [详细]
  • python的交互模式怎么输出名文汉字[python常见问题]
    在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就进入到Python交互模式,它的提示符是>>>,此时我们可以使用print() ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 本文总结了汇编语言中第五至第八章的关键知识点,涵盖间接寻址、指令格式、安全编程空间、逻辑运算指令及数据重复定义等内容。通过详细解析这些内容,帮助读者更好地理解和应用汇编语言的高级特性。 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细介绍了如何使用Maven高效管理多模块项目,涵盖项目结构设计、依赖管理和构建优化等方面。通过具体的实例和配置说明,帮助开发者更好地理解和应用Maven在复杂项目中的优势。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
author-avatar
逝去似水流年
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有