约瑟夫问题的变种 LA3882

题目大意:

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

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

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

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

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

设第一个删除的数的编号为x,则x= k %n-1 (注意是编号,真正删除的数为编号+1)

那么剩下的n-1个数可以组成一个新的约瑟夫环。

现在的编号是什么呢?显然:(令x+1=y ,就是说y= k%n)

y ,  y+1 , y+2  ...  n-1  , 0 , 1  ... y-2

把y放在第一个的目的是下一次从它开始数数。

重新开始数k个数.

你说重新?嗯。那么就可以这样重新编号:

y             -> 0

y+1            ->1

y+2            ->2

...

...

y-2          -> n-2

现在就变成了n-1个数(编号从0~n-2)的约瑟夫问题了!

假设z是最后n-1个数留下的编号,那么z’是n个人留下的编号,则显然z’=(z+y)% n

如何知道n-1个的解?往下递归就好了嘛,知道n-2即可

所以,有:

ans [1]=0;

ans [n] =(ans[n-1]+k) %n;

(可能有人要问了:上面不是z’=(z+y)% n吗?现在怎么变成 k了?因为y= k%n,模运算)

然后,答案要+1 (编号->数)

那么这一题第一次是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;
} 
时间: 2024-10-12 10:47:09

约瑟夫问题的变种 LA3882的相关文章

BestCoder Round #75

A题题目大意,一个给定矩形,每次一刀切出一个正方形,问可以切几刀 显然GCD改改就好. 一看数据范围,这不是C++入门练习题了么?那么GCD也懒得写了,于是噼里啪啦A了 为什么是GCD,题解的图很棒地解释了这个 发现以后这之类的问题说明都可以看看这张图. 暴力的代码: #include <cstdio> using namespace std; int m,n,ans; int main(int T){ scanf("%d",&T); while(T--){ ans

LA3882 约瑟夫数学递归法

首先,约瑟夫环的数学优化方法为: 为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号. 我们知道第一个人(编号一定是(m-1)%n) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):    k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2 并且从k开始报0.现在我们把他们的编号做一下转换: k --> 0 k+1 --

约瑟夫环以及其变种集合

最近在CF上补题,补到了一道关于约瑟夫环的题目(听都没听过,原谅我太菜) 就去好好学了一下,不过一般的题目应该是不会让你模拟过的,所以这次就做了一个约瑟夫环公式法变形的集合. 关于约瑟夫环的基础讲解,我个人认为最好的就是这篇了. 首先是最原始的约瑟夫环的题目: https://vjudge.net/problem/51Nod-1073(小数据规模) #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with

一个不简洁的约瑟夫环解法

约瑟夫环类似模型:已知有n个人,每次间隔k个人剔除一个,求最后一个剩余的. 此解法为变种,k最初为k-2,之后每次都加1. 例:n=5,k=3.从1开始,第一次间隔k-2=1,将3剔除,第二次间隔k-1=2,将1剔除.依此类推,直至剩余最后一个元素. 核心思路:将原列表复制多份横向展开,每次根据间隔获取被剔除的元素,同时将此元素存入一个剔除列表中.若被剔除元素不存在于剔除列表,则将其加入,若已存在,则顺势后移至从未加入剔除列表的元素,并将其加入.如此重复n-1次.面试遇到的题,当时只写了思路,没

约瑟夫问题——历史的真相

题目描述 你一定听说过约瑟夫问题,或者它的"变种"--猴子选大王等故事吧.但是,你知道约瑟夫问题的历史真相吗?约瑟夫是公元一世纪著名的历史学家.在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人俘虏,于是决定了一个流传千古的自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报到第3人该人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止.然而约瑟夫和他的朋友并不想遵从这个约定,约瑟夫要他的朋友先假装遵从,他将朋友与自

约瑟夫环问题小结

一 问题描述 约瑟夫环问题的基本描述如下:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为1的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,要求找到最后一个出列的人或者模拟这个过程. 二 问题解法 在解决这个问题之前,首先我们对人物进行虚拟编号,即相当于从0开始把人物重新进行编号,即用0,1,2,3,...n-1来表示人物的编号,最后返回的编号结果加上1,就是原问题的解(为什么这么做呢,下文有解释).而关于该问题的解

【c语言】数据结构(约瑟夫生者死者游戏的问题)

约瑟夫生者死者游戏:30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分:因此船长告诉大家,只有将全船一半的旅客投入海中,其余人才能幸免遇难.无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人开始,依次报数,数到第9个人,就把他投入大海中,然后从他的下一个人开始从1数起,数到第9个人,再将她投入大海,如此循环,直到剩下15个人乘客为止.问哪些位置是将被扔到大海的位置. 解法有许多种,可以用数组,应为涉及到删除操作,数组(顺序线性表)比较麻烦,但不必要删除,只需要给跳船的人(元素

算法系列:约瑟夫斯问题

约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环. 有{\displaystyle n}个囚犯站成一个圆圈,准备处决.首先从一个人开始,越过{\displaystyle k-2}个人(因为第一个人已经被越过),并杀掉第k个人.接着,再越过{\displaystyle k-1}个人,并杀掉第k个人.这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着. 问题是,给定了{\displaystyle n}和{

ytu 1067: 顺序排号(约瑟夫环)

1067: 顺序排号Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 31  Solved: 16[Submit][Status][Web Board] Description 有n人围成一圈,顺序排号.从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位. Input 初始人数n Output 最后一人的初始编号 Sample Input 3 Sample Output 2 HINT Source freepro