zoukankan      html  css  js  c++  java
  • uva3882

    约瑟夫问题的变形

    看了网上的题解,这题有一个trick就是每轮删完点后将剩下的点重新编号,从0编到n-1。

    这样操作之后,我们就可以对删点前后的两个状态进行递推了。

    假设我现在有一排点,编号为0到n-1,现在我从0开始数k个删掉第k个点,也就是删掉点k-1。

    剩下的点为0,1,2……k-2,k……,n-1

    我从k这个点开始重新编号,即:

    这样子问题具有相似性了。(因为同样是从0开始数到第k个删掉)

    那么怎么递推呢?

    可以看出,想要恢复上一轮的编号,只需要+k再整体%n即可

    如果记f[n] = n个数从0开始编号数到第k个删掉最后剩下的数的编号的话,

    f[n]  = (f[n-1] + k) % n;(注意这里的n是变化的)

    最后输出(m-k+1+f[n])%n。

    这个式子拆成两部分来解释,一部分是+1:

    因为我们设计的状态是从0开始的,然而题目是从1开始的,所以最后加1。

    另一部分是m-k:

    这是因为要删掉第m个,然而我们设计的状态是从0开始数k个删,这样如果我们加上m-k的话,就相当于成功地把m当成了第一个删的对象。(我们之前第一个删的对象是k嘛)(很难表达。。。见谅)

    综上输出(m-k+1+f[n])%n

    最后如果答案小于0,还要加上n。

    #include <cstdio>
    
    using namespace std;
    
    const int maxn = 10005;
    
    int n, k, m;
    
    int f[maxn];
    
    int main()
    {
        while(scanf("%d%d%d", &n, &k, &m) && n)
        {
            f[1] = 0;
            for (int i = 2; i <= n; i++)
                f[i] = (f[i - 1] + k) % i;
            int ans = (f[n] + m - k + 1) % n;
            if (ans <= 0) ans += n;
            printf("%d
    ", ans);
        }
        return 0;
    } 

    代码很简单,思路很复杂。

  • 相关阅读:
    Tensor总结
    Tensorflow池化
    conda操作
    KS值计算
    supervisor实践
    npm/yarn实践
    nni 环境搭建
    阿里云个人邮箱配置
    Jinja2宏使用
    利用VS code 远程调试 docker 中的 dotnet 应用
  • 原文地址:https://www.cnblogs.com/yohanlong/p/7754601.html
Copyright © 2011-2022 走看看