• [51nod1073]约瑟夫环


    解题关键:此题不需要模拟,可以用数学方法解决。

    无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂
    度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

    为了讨论方便,先把问题稍微改变一下,并不影响原意:

    问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号

    我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的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 --> 1
    k+2 --> 2
    ...
    ...
    k-2 --> n-2
    k-1 --> n-1

    变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根
    据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x=(x+k)%n

    如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的
    情况 ---- 这显然就是一个倒推问题!

    复杂度:$O(n)$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int main(){
     5     int n,m,f=0;
     6     cin>>n>>m;
     7     for(int i=2;i<=n;i++){
     8         f=(f+m)%i;
     9     }
    10     cout<<f+1<<endl;
    11     return 0;
    12 }
  • 相关阅读:
    IntentService使用以及源码分析
    Android HandlerThread源码解析
    Android Handler消息机制源码解析
    Gradle技术之四
    Android EditText实现小数点后几位的终级方案
    Gradle系列之三 Gradle概述以及生命周期
    Gradle系列之二 Groovy对文件的操作
    Gradle系列之一 Groovy语法精讲
    Context源码分析
    用EXCLE群发outlook邮件
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/6914732.html
Copyright © 2020-2023  润新知