只是问最后剩下的是哪个,而没有问具体是怎么删除的,所以不需要完全模拟,只需要模拟编号就好了。
一开始有n个,分别编号为 0,1,2,3,...n-1。
删除第k个,即编号为k-1的那个,那么删除后剩下 0,1,...k-2,k,...,n-1。
然后对n-1个物品重新编号,以便递归调用。
0 n-k
1 n-k+1
...
k-2 n-2
k 0
...
n-1 n-k-1
设旧编号为x,新编号为y,那么x=(y+k)%n。
f(n)代表n个物品时最后一个人的编号。
所以f(n)=(f(n-1)+k)%n
递归边界为f(1)=0
一开始有n个,分别编号为 0,1,2,3,...n-1。
删除第k个,即编号为k-1的那个,那么删除后剩下 0,1,...k-2,k,...,n-1。
然后对n-1个物品重新编号,以便递归调用。
0 n-k
1 n-k+1
...
k-2 n-2
k 0
...
n-1 n-k-1
设旧编号为x,新编号为y,那么x=(y+k)%n。
f(n)代表n个物品时最后一个人的编号。
所以f(n)=(f(n-1)+k)%n
递归边界为f(1)=0
在原版问题中,是第1个人开始报数,然后第k个人被删除。即从编号为0的人开始报数,然后编号为k-1的人被删除。
而在这题中是第m个人要先被删除,那么就要从第(m-k+1)个人开始报数,即编号为(m-k+n)%n的人开始报数。
因此答案为((m-k+f(n))%n+n)%n+1。大白书上的答案也是大同小异,只不过我是算出编号然后+1,它是算出第几个然后再把它变成正数。
%n这种东西要特别小心负数。
代码
#include<bits/stdc++.h>
using namespace std;
int n,k,m;
int f(int n)
{
if(n==1) return 0;
return (f(n-1)+k)%n;
}
int main()
{
while(scanf("%d %d %d",&n,&k,&m)==3&&(n+k+m))
{
int ans=(f(n)+m-k+1)%n;
if(ans<=0) ans+=n;
printf("%d\n",ans);
}
return 0;
}