hihocoder 数论三·约瑟夫问题

本文介绍约瑟夫问题的背景及其两种高效算法解决方案。通过递推公式和数学归纳法,详细解析了如何求解不同规模下的最优解,并提供AC代码实现。

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

题目1 : 数论三·约瑟夫问题

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

小Hi和小Ho的班级正在进行班长的选举,他们决定通过一种特殊的方式来选择班长。

首先N个候选人围成一个圈,依次编号为0..N-1。然后随机抽选一个数K,并0号候选人开始按从1到K的顺序依次报数,N-1号候选人报数之后,又再次从0开始。当有人报到K时,这个人被淘汰,从圈里出去。下一个人从1开始重新报数。

也就是说每报K个数字,都会淘汰一人。这样经过N-1轮报数之后,圈内就只剩下1个人了,这个人就作为新的班长。

举个例子,假如有5个候选人,K=3:

初始
0: 0 1 2 3 4
从0号开始报数,第1次是2号报到3
1: 0 1 - 3 4    	// 0 1 2, 2号候选人淘汰
从3号开始报数,第2次是0号报到3
2: - 1 3 4		// 3 4 0, 0号候选人淘汰
从1号开始报数,第3次是4号报到3
3: 1 3 -		// 1 3 4, 4号候选人淘汰
从1号开始报数,第4次是1号报到3
4: - 3			// 1 3 1, 1号候选人淘汰
  

对于N=5,K=3的情况,最后当选班长的人是编号为3的候选人。

小Ho:小Hi,我觉得当人数和K都确定的时候已经可以确定结果了。

小Hi:嗯,没错。

小Ho:我也想当班长,小Hi你能提前告诉我应该站在哪个位置么?

小Hi:我可以告诉你怎么去求最后一个被淘汰的位置,不过具体的值你得自己去求解。

小Ho:嗯,没问题,那么你快告诉我方法吧!

提示:约瑟夫问题

输入

第1行:1个正整数t,表示多组输入数据,1≤t≤100

第2..t+1行:每行2个正整数n,k,第i+1行表示第i组测试数据,2≤n≤1,000,000,000。2≤k≤1,000

输出

第1..t行:每行1个整数,第i行表示第i组数据的解

样例输入
2
5 3
8 3
样例输出
3
6
 
    
      
      
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long long N,M;
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		scanf("%lld%lld",&N,&M);
		long long f1 = 0;
		long long f2;
		long long X;
		if (M == 1)
		{
			printf("%lld\n",N-1);
		}
		else
		{
			for (long long i = 2; i <= N; ++ i)
			{
				if (f1 + M < i)   //表示很有可能跳过X个i
				{
					X = (i - f1) / M;  //能跳过多少个
					if (i + X < N)   //如果没有跳过n,就是i<=N
					{
						i = i + X;   //i直接到i+X
						f2 = (f1 + X*M);   //由于f1+X*M肯定<=i,所以这里不用%i
						f1 = f2;
					}
					else      //如果跳过了n,不能直接加X了,只需要加(N-i)个M即可
					{
						f2 = f1+(N-i)*M;
						f1 = f2;
						i = N;
					}
				}
				f2 = (f1 + M) % i;//如果f1+M>=i或者跳过上面的一些i之后还是要继续当前i对应的出列的人
				f1 = f2;
			}
			printf("%lld\n",f2);
		}
		
	}
	return 0;
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值