POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数)
ACM
题目地址:POJ 2886 Who Gets the Most Candies?
题意:
N 个小孩围成一圈,他们被顺时针编号为 1 到 N。每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的, 则是右手边的第 -A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。
分析:
- 线段树模拟约瑟夫环。第k个小孩根据手牌叫下一个小孩的时候,可以计算出那个是从0开始的第几个,然后就转化为排队问题了。
- 然后就是问谁最多的糖果了,其实就是问前n个数中的高合成数。可以先预处理高合成数,或者直接暴力处理每个数的因子个数。
代码:
/*
* Author: illuz <iilluzen[at]gmail.com>
* Blog: http://blog.csdn.net/hcbbt
* File: 2886.cpp
* Create Date: 2014-08-06 14:10:51
* Descripton: segment tree
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define lson(x) ((x) << 1)
#define rson(x) ((x) << 1 | 1)
typedef long long ll;
const int N = 500100;
const int ROOT = 1;
int n, k;
int maxid, maxnum;
int tab[N];
char name[N][15];
int card[N];
// below is sement point updated version
struct seg {
ll w;
};
struct segment_tree {
seg node[N << 2];
void update(int pos) {
node[pos].w = node[lson(pos)].w + node[rson(pos)].w;
}
void build(int l, int r, int pos) {
if (l == r) {
node[pos].w = 1;
return;
}
int m = (l + r) >> 1;
build(l, m, lson(pos));
build(m + 1, r, rson(pos));
update(pos);
}
// remove the point that the sum of [0, it] is x, return its id
int remove(int l, int r, int pos, ll x) {
if (l == r) {
node[pos].w = 0;
return l;
}
int m = (l + r) >> 1;
int res;
if (x <= node[lson(pos)].w)
res = remove(l, m, lson(pos), x);
else
res = remove(m + 1, r, rson(pos), x - node[lson(pos)].w);
update(pos);
return res;
}
} sgm;
// record the num of division, O(nlogn)
void pre() {
repf (i, 1, N - 1) {
for (int j = i; j < N; j += i)
tab[j]++;
}
}
void getmaxnum(int n) {
maxid = 1;
maxnum = tab[1];
repf (i, 2, n) {
if (tab[i] > maxnum) {
maxnum = tab[i];
maxid = i;
}
}
}
int main() {
pre();
while (~scanf("%d%d", &n, &k)) {
getmaxnum(n);
sgm.build(1, n, ROOT);
repf (i, 1, n) {
scanf("%s%d", name[i], &card[i]);
}
int pos, rest = n;
repf (i, 1, maxid) {
pos = sgm.remove(1, n, ROOT, k);
if (--rest == 0)
break;
if (card[pos] > 0)
k = (k - 1 + card[pos] - 1) % rest + 1;
else
k = ((k - 1 + card[pos]) % rest + rest) % rest + 1;
}
printf("%s %d\n", name[pos], maxnum);
}
return 0;
}