Josephus again HDU

来源:互联网 发布:北京赛车软件下载 编辑:程序博客网 时间:2024/06/08 17:26

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到n1标号的人中,最后留下的那个人的编号,且是数到第m1(从第0个开始数)个离开
有递推公式:

f(n)=(f(n1)+m)%n

所以答案就是f(n)+1
但是这里的n非常大,线性递推是不可行的,所以我们得优化一下递推过程。

我们看一下递推是,如果(f(n1)+m)远远小于n,那么实际上可以看成没有经过取余,而是一直累加m,直到(f(n1)+m)>n,设f(n1)num
我们分:

num+m>=n
num+m<n

讨论,如果是第一种只要正常递推即可,第二种,我们只要看他可以累加到多少个m。
设可以累加x个m,即满足
num+xm<i+x1
,这里x至少会取到1,因为这第二种情况讨论的条件
所以:
x=inum1m1(x1)

若此时(i+x1)>n,那么num+m(n+1i)就是答案

#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;}