In our Jesephus game, we start with n people numbered 1 to n around a circle, and we eliminated every k remaining person until only one survives. For example, here’s the starting configuration for n = 10, k = 2, The elimination order is 2, 4, 6, 8, 10, 3, 7, 1, 9. So 5 survives.The problem: determine the survivor’s number , J(n, k).
Input
There are multiple cases, end with EOF
each case have two integer, n, k. (1<= n <= 10^12, 1 <= k <= 1000)
Output
each case a line J(n, k)
Sample Input
10 2
10 3
Sample Output
5
4
问题显而易见,对于这种问题,我们是有递推公式的;
假设
f(n)
的定义为从0到
n−1
标号的人中,最后留下的那个人的编号,且是数到第
m−1
(从第0个开始数)个离开
有递推公式:
所以答案就是
f(n)+1
但是这里的n非常大,线性递推是不可行的,所以我们得优化一下递推过程。
我们看一下递推是,如果
(f(n−1)+m)
远远小于n,那么实际上可以看成没有经过取余,而是一直累加
m
,直到
我们分:
讨论,如果是第一种只要正常递推即可,第二种,我们只要看他可以累加到多少个m。
设可以累加x个m,即满足
所以:
若此时 (i+x−1)>n ,那么 num+m∗(n+1−i) 就是答案
#include<iostream>
#include<cstdio>
using namespace std;
int f[100000];
long long solve(long long n,long long m)
{
long long i=2;
long long num=0;
for(;;)
{
if(i>n)
break;
if(num+m>=i)
{
num=(num+m)%i;
i++;
}
else
{
long long x=(i-num-1)/(m-1);
if((i-num-1)%(m-1)==0)
x--;
if(i+x-1>n)
{
return num+(n+1-i)*m+1; //这里得出答案和实际都差1,所以需要在加1
}
else
{
num+=x*m;
i+=x;
}
}
}
return num+1;
}
int main()
{
long long n,m;
while(scanf("%lld%lld",&n,&m)==2)
{
if(m==1)
printf("%lld\n",n);
else
printf("%lld\n",solve(n,m));
}
return 0;
}