题目链接: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