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

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

原文地址:https://www.cnblogs.com/kedebug/p/2858102.html