POJ 2886 Who Gets the Most Candies?
2012-01-31 15:17
405 查看
题意:
N个孩子顺时针坐成一个圆圈且从1到N编号,每个孩子手中有一张标有非零整数的卡片。第K个孩子先出圈,如果他手中卡片上的数字A大于零,下一个出圈的是他左手边第A个孩子。否则,下一个出圈的是他右手边第(-A)个孩子。第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数。求得到糖果数最多的是哪个孩子及得到多少糖果。
分析:
出圈过程有点类似约瑟夫环。假设当前出圈的是剩余孩子中的第K个,他手中的数字为A。若A大于零,下一个出圈的就应该是剩余孩子中的第(K-1+A-1)%n+1个;若A小于零,下一个出圈的就应该是剩余孩子中的第((K-1+A)%n+n)%n+1个。问题的关键是如何求得出圈孩子的原始位置,这里我用的是线段树。线段树的每个节点的sum存储了所在区间还有多少孩子留下,查询节点rt中第num个孩子的原始位置时,如果num<=st[rt<<1].sum,则在左孩子节点中查询第num个孩子的原始位置;否则在右孩子节点中查询第num-st[rt<<1].sum个孩子的原始位置。
另外,本题还用到了反素数。反素数的定义:对于任何正整数x,其约数的个数记做g(x)。例如g(1)=1,g(6)=4。如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数。对于本题,设p为不大于N的反素数,则第p个出圈的孩子得到的糖果最多,为p的约数个数。
代码:
N个孩子顺时针坐成一个圆圈且从1到N编号,每个孩子手中有一张标有非零整数的卡片。第K个孩子先出圈,如果他手中卡片上的数字A大于零,下一个出圈的是他左手边第A个孩子。否则,下一个出圈的是他右手边第(-A)个孩子。第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数。求得到糖果数最多的是哪个孩子及得到多少糖果。
分析:
出圈过程有点类似约瑟夫环。假设当前出圈的是剩余孩子中的第K个,他手中的数字为A。若A大于零,下一个出圈的就应该是剩余孩子中的第(K-1+A-1)%n+1个;若A小于零,下一个出圈的就应该是剩余孩子中的第((K-1+A)%n+n)%n+1个。问题的关键是如何求得出圈孩子的原始位置,这里我用的是线段树。线段树的每个节点的sum存储了所在区间还有多少孩子留下,查询节点rt中第num个孩子的原始位置时,如果num<=st[rt<<1].sum,则在左孩子节点中查询第num个孩子的原始位置;否则在右孩子节点中查询第num-st[rt<<1].sum个孩子的原始位置。
另外,本题还用到了反素数。反素数的定义:对于任何正整数x,其约数的个数记做g(x)。例如g(1)=1,g(6)=4。如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数。对于本题,设p为不大于N的反素数,则第p个出圈的孩子得到的糖果最多,为p的约数个数。
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> using namespace std; const int maxn = 500100; char name[maxn][11]; int val[maxn]; /* a为反素数表,b为对应的约数个数 */ int a[37]={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,500001}; int b[37]={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,1314521}; struct Node { int l, r, sum; }st[maxn<<2]; void build(int l, int r, int rt) { st[rt].l = l; st[rt].r = r; st[rt].sum = r - l + 1; if (l == r) return ; int m = (l + r) >> 1; build(l, m, rt << 1); build(m + 1, r, rt << 1 | 1); } /* 求当前留下的孩子中第num个孩子的原始位置 */ int query(int num, int rt) { st[rt].sum--; if (st[rt].l == st[rt].r) { return st[rt].l; } if (num <= st[rt<<1].sum) return query(num, rt << 1); return query(num - st[rt<<1].sum, rt << 1 | 1); } int main() { int n, k; while (scanf("%d %d", &n, &k) != EOF) { int i = 0, Max = 0, p = 0; /* 第p个出去的孩子得到最多的糖果,为Max */ while (a[i] <= n) i++; p = a[i-1]; Max = b[i-1]; build(1, n, 1); for (i = 1; i <= n; ++i) { scanf("%s %d", &name[i], &val[i]); } int idx; /* idx为当前出去的孩子的原始位置 */ for (i = 0; i < p; ++i) /* 只要求出第p个出去的孩子即可 */ { n--; idx = query(k, 1); if (n == 0) break; if (val[idx] > 0) k = (k-1+val[idx]-1)%n+1; else k = ((k-1+val[idx])%n+n)%n+1; } printf("%s %d\n", name[idx], Max); } return 0; }
相关文章推荐
- POJ2886--Who Gets the Most Candies?
- poj 2886 Who Gets the Most Candies?(线段树和反素数)
- POJ 2886 Who Gets the Most Candies?
- POJ 2886 Who Gets the Most Candies? (约瑟夫环+反素数+线段树)
- POJ-2886-Who Gets the Most Candies?
- POJ 2886 Who Gets the Most Candies?
- POJ 2886 Who Gets the Most Candies?(线段树)
- POJ 2886:Who Gets the Most Candies?
- 【POJ 2886】 Who Gets the Most Candies?(反素数求最大因子数+线段树)
- Who Gets the Most Candies?----POJ_2886----线段树之单点更新
- POJ2886-Who Gets the Most Candies?-模拟约瑟夫环+反素数表(线段树上二分+爆搜打表)
- poj2886 Who Gets the Most Candies? 线段树加反素数
- poj 2886 Who Gets the Most Candies?
- poj 2886 Who Gets the Most Candies?
- [poj 2886] Who Gets the Most Candies[线段树][约瑟夫环][反素数]
- POJ 2886 Who Gets the Most Candies?
- POJ 2886 Who Gets the Most Candies?
- poj 2886 Who Gets the Most Candies?(线段树)
- 【POJ】2886 Who Gets the Most Candies?
- POJ 2886 Who Gets the Most Candies?