POJ 2886 Who Gets the Most Candies?(单点更新 + 约瑟夫环)

来源:互联网 发布:linux中压缩命令 编辑:程序博客网 时间:2024/06/04 17:52

题目链接: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 | 1const 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;}
0 0
原创粉丝点击