• 51nod1073(约瑟夫环)


    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1073

    题意: 中文题诶~


    思路: 直接模拟的话O(n*k)的时间复杂度,按照套路来的话这样的题一般是能找规律的;
    我们先将n个人的编号改成0~n-1(别问为什么,套路而已),那么第1次报到号码为k-1的人出列,圈里还剩下n-1个人
    我们对比一下出列前后的编号:

    出列前: 0, 1, 2, 3, 4, 5, 6, ...k-2, k-1, k... n-1
    出列后: n-k+1,..................n-2, , 1... n-k

    我们可以发现留下的人编号和留下来之前是一一对应的,那么要是能找到对应关系的话问题就迎刃而解了,不过现在数据太多了不好找
    (偶就是这里找错了规律然后只过了样例),我们接着往下想想...
    按照前面的规律,第n次报数时只有一个人,我们给他重新编号为0.前面我们也知道了某一轮某个人的编号和上一轮是对应的,最后留下的人此时的编号为0,
    那么只要我们由它上溯并找到它在第一轮时的编号答案就出来了啦~
    我们用f(x)表示最后留下来那个人在第n-x+1轮中的编号(这样做我们就是由f(1)推f(n),更直观一些,反之由f(n)推f(1)也是可以的),那么f(n)+1就是
    最终答案了啦.很显然有f(1)=0(因为此时只剩下一个人了嘛),接下来我们需要找到两轮编号之间的映射关系,这个可以有枚举k和x得到,这里就不写枚举
    过程了啦~
    最后我们可以得到公式 f(x)=(f(x-1)+k)%x;

    代码 :
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main(void){
     5     int gg, n, k;
     6     cin >> n >> k;
     7     gg=0;
     8     for(int i=2; i<=n; i++){
     9         gg=(gg+k)%i; //前面说的f(x)只是为了我们更直观地理解,其实直接用一个变量保存上一轮序号就可以了
    10     }
    11     cout << gg+1 << endl;
    12     return 0;
    13 }
    
    
  • 相关阅读:
    浅析Java CompletionService
    经验总结13--EF配置
    消息摘要算法-HMAC算法
    03012_预处理对象executeQuery方法(实现数据库的查询)
    GO学习笔记:函数defer
    GO学习笔记:函数传值与传指针
    GO学习笔记:函数作为值、类型
    GO学习笔记:函数Panic和Recover
    GO学习笔记:import
    GO学习笔记:struct类型
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/6202200.html
Copyright © 2020-2023  润新知