• POJ 2886 Who Gets the Most Candies(线段树模拟约瑟夫环)


    题意:

    n个人玩约瑟夫游戏,求第p个(p为<=n的最大反质数)被踢的人的原始序号。

    思路:

    1. 线段树区间是1~n,每个节点表示区间剩余的人数,初始化为每个区间为1个人。

    2. 关于k值的求解稍微有点绕:因为取模运算结果总是0~mod-1,而我们的区间是1-mod,所以在取模之前要-1,求出结果后再+1

    3. 用相对位移的概念来理解,如果k是正数,则p后面的第k个数要出局,此时相对位移是:p + (k - 1) - 1,如果k是负数,则是p前面的,位移是:p + k - 1

    #include <cstdio>
    
    #define lhs l, m, rt << 1
    #define rhs m + 1, r, rt << 1 | 1
    
    const int maxn = 500010;
    
    struct _Joseph {
        char name[12];
        int value;
    } boy[maxn];
    
    int seg[maxn << 2];
    
    void PushUp(int rt)
    {
        seg[rt] = seg[rt << 1] + seg[rt << 1 | 1];
    }
    
    void Build(int l, int r, int rt)
    {
        if (l == r)
            seg[rt] = 1;
        else
        {
            int m = (l + r) >> 1;
            Build(lhs);
            Build(rhs);
            PushUp(rt);
        }
    }
    
    int Update(int delta, int l, int r, int rt)
    {
        int ret;
        if (l == r)
        {
            seg[rt] = 0;
            ret = r;
        }
        else
        {
            int m = (l + r) >> 1;
            if (delta <= seg[rt << 1])
                ret = Update(delta, lhs);
            else
                ret = Update(delta - seg[rt << 1], rhs);
            PushUp(rt);
        }
        return ret;
    }
    
    const int antiprime[] = {
        1,2,4,6,12,24,36,48,60,120,180,240,360,
        720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,
        27720,45360,50400,55440,83160,110880,166320, 221760, 
        277200, 332640, 498960, 554400, 665280};
    const int factorNum[] = {
        1, 2, 3, 4, 6, 8, 9, 10, 12, 16, 18, 20, 
        24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 84, 
        90, 96, 100, 108, 120, 128, 144, 160, 168, 180, 192, 200, 216, 224};
    
    int main()
    {
        int n, k;
    
        while (~scanf("%d %d", &n, &k))
        {
            for (int i = 1; i <= n; ++i)
                scanf("%s %d", boy[i].name, &boy[i].value);
    
            Build(1, n, 1);
    
            int i = 0;
            while (antiprime[i] <= n)
                ++i;
    
            int times = antiprime[--i];
    
            int pos = 0;
            boy[pos].value = 0;
    
            while (times--)
            {
                int mod = seg[1];
                if (boy[pos].value > 0)
                    k = ((k + boy[pos].value - 2) % mod + mod) % mod + 1;
                else 
                    k = ((k + boy[pos].value - 1) % mod + mod) % mod + 1;
                pos = Update(k, 1, n, 1);
            }
    
            printf("%s %d\n", boy[pos].name, factorNum[i]);
        }
        return 0;
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    Git与GitHub的基本使用
    HTML&CSS基础-外边框
    HTML&CSS基础-内边框
    SHELL脚本编程变量输入
    GoLang基础数据类型-切片(slice)详解
    GoLang基础数据类型--->数组(array)详解
    SHELL脚本编程的运算符
    SHELL脚本编程变量详解
    HTML&CSS基础-边框简写属性
    GoLang基础数据类型--->字符串处理大全
  • 原文地址:https://www.cnblogs.com/kedebug/p/2858102.html
Copyright © 2020-2023  润新知