• 数论三·约瑟夫问题


    #1296 : 数论三·约瑟夫问题

    时间限制: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

    首先第一种递推:f[i]表示有i个人时,最终的结果是哪一个。
    递推式:f[1]=0,f[n]=(f[n-1]+k)mod
    n
    用数学归纳法证明。
    这样的复杂度为O(n),在n比较大的情况下会TLE。
    第二种递推:
      ret=juse(n-n/k,k);
      if(ret<n%k)
    return (ret+n/k*k)%n;
      else
    return (ret+n/k*k+(ret-(n%k))/(k-1))%n;
    感性地理解一下,若这个ret小于n%k,则代表在求出f[n]时,中间的有缺掉的不影响答案,否则需要加上中间这些缺掉的。
     1 #include<set>
     2 #include<map>
     3 #include<queue>
     4 #include<stack>
     5 #include<ctime>
     6 #include<cmath>
     7 #include<string>
     8 #include<vector>
     9 #include<cstdio>
    10 #include<cstdlib>
    11 #include<cstring>
    12 #include<iostream>
    13 #include<algorithm>
    14 using namespace std;
    15 int juse(int n,int k){
    16   if(n==1) return 0;
    17   int ret=0;
    18   if(n<k){
    19     for(int i=2;i<=n;i++)
    20       ret=(ret+k)%i;
    21     return ret;
    22   }
    23   ret=juse(n-n/k,k);
    24   if(ret<n%k) return (ret+n/k*k)%n;
    25   else return (ret+n/k*k+(ret-(n%k))/(k-1))%n;
    26 }
    27 int main()
    28 {
    29   freopen("!.in","r",stdin);
    30   freopen("!.out","w",stdout);
    31   int T,n,k;
    32   scanf("%d",&T);
    33   while(T){
    34     T--;
    35     scanf("%d%d",&n,&k);
    36     printf("%d
    ",juse(n,k));
    37   }
    38   return 0;
    39 }
    
    
    
    
    
  • 相关阅读:
    校验身份证有效性
    JAVA实现redis超时失效key 的监听触发
    Java8中时间日期库的20个常用使用示例
    ppt制作元素采集
    查找数据的网站
    在centos7中python3的安装注意
    使用yum安装不知道到底安装在什么文件夹
    linux为什么不可以添加硬链接
    五一之起一台服务器玩玩-花生壳配置
    centos6.5-vsftp搭建
  • 原文地址:https://www.cnblogs.com/pantakill/p/6633857.html
Copyright © 2020-2023  润新知