zoukankan      html  css  js  c++  java
  • 【2018沈阳现场赛k】Let the Flames Begin

    题意

    有n个人围成一圈,编号1到n,从1号开始报数,每报到第k个,此人出列,下一个人再从1开始报数,求第m个出列的人的编号(n,m,k ≤ 1e18, m,k其中一个小于1e6)

    分析

    我们知道,约瑟夫环的出队是有O(n)的递推算法的:f(n) = (f(n-1)+k-1)%n 约瑟夫环数学推导

    但是这里是最后一个出列的人的情况(n个人第n个出列)

    考虑一下n个人第m个出列,设状态为f(n,m),我们可以假设在m个人中再插上n-m个人,他们都比前m个人晚出队(具体放在哪里不用关心,只要认为他们一定不会先出队就行了),那么递推式就和刚刚的雷同 f(n,m) = (f(n-1,m-1)+k-1)%n,这个式子可以在o(m)的时间内求出答案,适用于m≤1e6的情况

    那么当m在1e18的范围内,该怎么办呢?

    观察当前递推式,每次都是+k,当超过n的范围时,进行取模运算,可以发现,当k<<n时,在很多次递推操作中都是不需要取模的,而是只有+k操作,那么我们其实可以吧加法转化成乘法来加速

    令add = n-m,考虑当前为f(x+add,x)执行t次后需要取模:

    f(x+add+t,x+t) = (f(x+add,x) + (t*k)-1)%(x+add+t)+1

    为什么这里的模数在一直变化,还可以这么干呢?因为模数每次只增加1,而f每次增加k,所以当k>1的时候,一定会越来越接近模数,直到超过它,当k=1的时候特判就好

    计算t值:

    一下简写f(x+add,x)为f

    f + (t*k)-1 ≥ x+add+t

    解得 t ≥ (x+add-f+1) / (k-1)

    从这里也可以看出k=1是需要特判的

    解出最小t,更新状态 x = x + t

    这个复杂度我也不会算了,但感觉不会太大

    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll n,m,k;
     5 int main() {
     6     ios::sync_with_stdio(false);
     7     int _,ca=0;cin>>_;
     8     while(_--) {
     9         cin>>n>>m>>k; 
    10         ll ans = (k-1)%(n-m+1)+1;
    11         if(k==1) ans = m;
    12         else if(k >= m) {
    13             for(ll i=2;i<=m;i++) 
    14                 ans = (ans + k -1)%(i+n-m)+1;
    15         }
    16         else {
    17             ll now = 1;ll a = n-m;
    18             while(now < m) {
    19                 ll d = (ll)ceil((now + a - ans)*1.0/(k-1));
    20                 if(d == 0) d++;
    21                 if(now+d >= m) {   d = m-now;}
    22                 now +=d;ll mod = (now+a);
    23                 ans = (ans + k*d%mod-1+mod)%mod+1;
    24             }
    25         }
    26         cout<<"Case #"<<++ca<<": "<<ans<<endl;
    27     }
    28 }
  • 相关阅读:
    es5预览本地文件、es6练习代码演示案例
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 838 推多米诺(暴力模拟)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 837 新21点(DP)
    Java实现 LeetCode 836 矩形重叠(暴力)
    Subversion under Linux [Reprint]
    Subversion how[Reprint]
  • 原文地址:https://www.cnblogs.com/greenty1208/p/9968462.html
Copyright © 2011-2022 走看看