码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 2886 Who Gets the Most Candies?

时间:2015-05-14 14:15:44      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:单点更新   线段树   

题目链接:http://poj.org/problem?id=2886

题意:N个人坐成一个圈,每个人都有个值A代表这他左边或右边的第A个人出圈,刚开始第k个人出圈。第i个人出圈得到价值为i的因子数的个数。求出圈价值最大的那个人。

思路:因为数据N为500000,所以需要利用线段树。不需要考虑N个人坐成一圈,认为N个人排成一个队列。每次更新当前队列中第k个人出圈,得到出圈人的下标。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <string>
using namespace std;

#define LSON l, m, rt << 1
#define RSON m + 1, r, rt << 1 | 1
const int maxn = 500005;

struct person {
    char name[15];
    int a;
}p[maxn];

int sum[maxn << 2];
int g[maxn];

void pushup(int rt) {
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void build(int l, int r, int rt) {
    if (l == r) {
        sum[rt] = 1;
        return ;
    }
    int m = (l + r) >> 1;
    build(LSON);
    build(RSON);
    pushup(rt);
}

int update(int x, int l, int r, int rt) {
    int res;
    if (l == r) {
        sum[rt]--;
        return res = l;
    }
    int m = (l + r) >> 1;
    if (x <= sum[rt << 1]) res = update(x, LSON);
    else res = update(x - sum[rt << 1], RSON);
    pushup(rt);
    return res;
}

void init() {
    memset(g, 0, sizeof(g));
    for (int i = 1; i <= 500000; i++) {
        g[i]++;
        for (int j = 2 * i; j <= 500000; j += i)
            g[j]++;
    }
}

int getMax(int n, int& id) {
    int res = g[1];
    for (int i = 1; i <= n; i++)
        if (g[i] > g[id]) {
            id = i;
            res = g[i];
        }
    return res;
}

int main() {
    int n, k;
    init();
    while (scanf("%d%d", &n, &k) != EOF) {
        getchar();
        int id = 1;
        int ans = getMax(n, id);
        for (int i = 1; i <= n; i++)
            scanf("%s%d", p[i].name, &p[i].a);

        int ps;
        //ps存储当前第k个出圈人的下标
        build(1, n, 1);
        for (int i = 1; i <= id; i++) {
            ps = update(k, 1, n, 1);
            int before = k - 1;
            int back = n - i - (k - 1);
            if (i == id) continue;
            if (p[ps].a > 0) {
                if (p[ps].a <= back)
                    k = before + p[ps].a;
                else {
                    int t = (p[ps].a - back) % (n - i);
                    k = (t == 0 ? (n - i) : t);
                }
            }
            else {
                p[ps].a = - p[ps].a;
                if (before >= p[ps].a)
                    k = before - p[ps].a + 1;
                else {
                    int t = (p[ps].a - before) % (n - i);
                    k = (n - i) - (t == 0 ? (n - i) : t) + 1;
                }
            }
        }

        printf("%s %d\n", p[ps].name, ans);
    }
    return 0;
}

POJ 2886 Who Gets the Most Candies?

标签:单点更新   线段树   

原文地址:http://blog.csdn.net/u014357885/article/details/45719813

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!