• ACM-ICPC 2018 沈阳赛区现场赛 K. Let the Flames Begin (约瑟夫环问题)


    题目链接:

    题意:有 n 个人围成一个圈,从 1 开始报到第 k 个人出环,问第 m 个出环的人是谁,n、m、k <= 1e18 且 min(m,k)<= 2e6。

    题解:容易得出O(m)的递推公式 f[n][m] = (f[n-1][m-1] + k - 1)% n + 1,初始状态 f[n-m+1][1]容易得出,当 m 小的时候用该公式计算。考虑 k 大 m 小的情况下,递推式的取膜很多情况下没有用到,可以用乘法代替加法加速递推的过程:

    当前状态为f[a][b] = c, 经过 x 次加法后的状态为 f[a+x][b+x] = c + k * x,假设经过 x 次加法之后需要取模,有

    c + k * x > a + x   →   x > (a - c)/ (k - 1)   

    得到该不等式后便可以计算出另一种情况了,还要注意 k = 1 需要特判。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define ull unsigned long long
     5 #define mst(a,b) memset((a),(b),sizeof(a))
     6 #define mp(a,b) make_pair(a,b)
     7 #define pi acos(-1)
     8 #define pii pair<int,int>
     9 #define pb push_back
    10 const int INF = 0x3f3f3f3f;
    11 const double eps = 1e-6;
    12 const int MAXN = 2e6 + 10;
    13 const int MAXM = 1e8 + 10;
    14 const ll mod = 1e9 + 7;
    15 
    16 ll f[MAXN];
    17 
    18 int main() {
    19 #ifdef local
    20     freopen("data.txt", "r", stdin);
    21 //    freopen("data.txt", "w", stdout);
    22 #endif
    23     int cas = 1;
    24     int t;
    25     scanf("%d",&t);
    26     while(t--) {
    27         ll n,m,k;
    28         scanf("%lld%lld%lld",&n,&m,&k);
    29         printf("Case #%d: ",cas++);
    30         if(m <= k) {
    31             f[1] = k % (n - m + 1);
    32             if(f[1] == 0) f[1] = n - m + 1;
    33             for(ll i = 2; i <= m; i++)
    34                 f[i] = (f[i - 1] + k - 1) % (n - m + i) + 1;
    35             printf("%lld
    ",f[m]);
    36         } else {
    37             if(k == 1) printf("%lld
    ",m);
    38             else {
    39                 ll a = n - m + 1, b = 1;
    40                 ll c = k % a, x = 0;
    41                 if(c == 0) c = a;
    42                 while(b + x <= m) {
    43                     a += x, b += x, c += k * x;
    44                     c %= a;
    45                     if(c == 0) c = a;
    46                     x = (a - c) / (k - 1) + 1;
    47                 }
    48                 c += (m - b) * k;
    49                 c %= n;
    50                 if(c == 0) c = n;
    51                 printf("%lld
    ",c);
    52             }
    53         }
    54     }
    55     return 0;
    56 }
  • 相关阅读:
    【转载】openCV轮廓操作
    求两个已排序数组的中位数
    朴素贝叶斯分类
    Different Ways to Add Parentheses
    QSerialPort
    opencv鼠标绘制直线 C++版
    Word Break
    C++中 指针 与 引用 的区别
    敲入url到浏览器后会发生什么
    Sort List 分类: leetcode 算法 2015-07-10 15:35 1人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/scaulok/p/9911819.html
Copyright © 2020-2023  润新知