Jzoj5421 嘟嘟噜

博客探讨了如何解决约瑟夫问题的10^9版,提出了在m≤10^5的情况下优化O(n)算法,通过观察i大于m时步骤合并的规律,将复杂度降低到近似O(√n),利用了数论和映射的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于众所周知的原因, 冈部一直欠真由理一串香蕉.
为了封上真由理的嘴, 冈部承诺只要真由理回答出这个问题, 就给她买一车的香蕉:
一开始有n 个人围成一个圈, 从1 开始顺时针报数, 报出m 的人被机关处决. 然后下一个人再从1 开始报数, 直到只剩下一个人.
红莉栖: “这不就是约瑟夫问题吗...”
伦太郎: “助手你给我闭嘴!”
真由理虽然已经晕头转向了, 但听到有一车的香蕉, 两眼便放出了光芒.

约瑟夫问题:10^9版,m<=10^5

我们知道有一个O(n)的算法:s=(s+m)%i {i=1~n}

然而这样只能70分,我们需要改进算法

我们发现当i大于m的时候,其实有些步骤是可以合并为一步的,这个和反演里面用的那个除法很像

那我们根据当前i-s%i可以得出,接下来(i-s%i)/m步是可以合为一步走的,在接下来这些过程中,取模不会改变s+m的值

让后就可以乱搞,复杂度O(玄学)≈O(√n)

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,s=0,T;
int main(){
	freopen("mayuri.in","r",stdin);
	freopen("mayuri.out","w",stdout);
	for(scanf("%d",&T);T--;){
		s=0;
		scanf("%d%d",&n,&m);
//		for(int i=2;i<=n;++i) s=(s+m)%i;
		for(int i=2,p;i<=n;){
			p=(i-s-1)/m+1;
			if(i+p>n) p=n-i+1;
			s=(s+m*p)%(i+p-1);
			i=i+p;
		}
		printf("%d\n",++s);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值