约瑟夫问题的变种 LA3882

题目大意:

N个数排成一圈,第一次删除m,以后每k个数删除一次,求最后一被删除的数。

 

如果这题用链表或者数组模拟整个过程的话,时间复杂度都将高达O(nk),而n<=10000,k<=10000 目测会直接TLE。

那么有没有其他的方法呢?答案是有的。

 

我们先忽略掉m, 分析一下每k个数删除一次,那就是经典的约瑟夫问题了。

那么,将每个数(1~n)按顺序编号为0~n-1

设第一个删除的数的编号为x,删除x后,剩下的n-1个数可以组成一个新的约瑟夫环

重新为新的环编号,原先为x+1的现在编号变为0,x+2变为1......

那么在新的环中的一个编号为p的数实际上就是原先环中编号为(p+k)%n的数(画图推算)

设f(i)为共有i个数时(0~i-1的环)最后留下的数是多少

则 f(i)=(f(i-1)+k)%n

相当于把i-1环的编号推算成i环的编号

 

那么这一题第一次是m怎么办呢?

也很简单,我们每次都移动K ,有n个数,那么答案就是ans[n]

但是第一次移动的是m,所以后面的移动都有个恒定的差距(k-m)

所以答案为:(ans[n] – (k – m) +1)% n (注意可能小于0 ,这时候要加上n)

 

#include<iostream>
#define Size 1000005
using namespace std;

int n,m,k;
int f[Size];

int main(){
    cin>>n>>k>>m;
    
    f[1]=0;
    for(int i=2;i<=n;i++){
        f[i]=(f[i-1]+k)%i;
    }
    
    int ans=(m-k+1+f[n])%n;
    if(ans<1)ans+=n;
    cout<<ans;
    
    return 0;
} 

 

posted @ 2016-04-19 21:28  FuTaimeng  阅读(451)  评论(0编辑  收藏  举报