POJ 2886 Who Gets the Most Candies? 线段树
2013-06-13 15:01
435 查看
/** * @file main.cpp * @brief 线段树+反质数理论 * 基本思路是模拟约瑟夫环问题,求出第p个出圈的小朋友 * 而p的值是小于等于小朋友总数n的最大的反质数 * * 不对反质数理论尽心更深探究,因为现在进行线段树以及树状数组专题训练 * * 基本算法是树状数组,每一个区间用以表示该区间内还剩下多少个小朋友, * 例如输入数据: * 4 2 * Tom 2 * Jack 4 * Mary -1 * Sam 1 * * 1. 初始树: * 1-4[4] * / \ * 1-2[2] 3-4[2] * / \ / \ * 1[1] 2[1] 3[1] 4[1] * * * 2. 第一轮出队, k==2,2号小朋友(index=2)出队后: * 1-4[3] * / \ * 1-2[1] 3-4[2] * / \ / \ * 1[1] 2[0] 3[1] 4[1] * * 由小朋友k算下一个小朋友序号的方法是: * if num > 0: * k = k + num - 1 (因为自己要出队) * else * k = k + num * * 根据 Jack 4以及k==2计算得出k==2 * * 3. 第二轮出队,又是2号小朋友(index=3)出队: * 1-4[2] * / \ * 1-2[1] 3-4[1] * / \ / \ * 1[1] 2[0] 3[0] 4[1] * * 根据 Mary -1以及k==2计算k==1 * * 4. 第三轮出队,1号小朋友(index=1)出队 * 1-4[1] * / \ * 1-2[0] 3-4[1] * / \ / \ * 1[0] 2[0] 3[0] 4[1] * * 5. 最终 * 1-4[0] * / \ * 1-2[0] 3-4[0] * / \ / \ * 1[0] 2[0] 3[0] 4[0] * * @author yekeren * @version 1.0.0 * @date 2013-06-13 */ #include <stdio.h> #define LEFT(x) (((x) << 1) + 1) #define RIGHT(x) (((x) << 1) + 2) ///<小朋友名字及编号 struct child_t { char name[11]; int num; } child[510001]; ///<树状数组 int range[1100001] = { 0 }; ///<反质数及其约数个数 int rprime[] = { 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,554400 }; int fact[] = { 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,216 }; /** * @brief 建立树状数组 * @param root * @param left * @param right */ void build(int root, int left, int right) { range[root] = right - left + 1; if (left == right) { return; } int mid = (left + right) >> 1; build(LEFT(root), left, mid); build(RIGHT(root), mid + 1, right); } /** * @brief 查找圈中的第k个小朋友 * @param root * @param left * @param right * @param k * @return */ int find(int root, int left, int right, int k) { while (left < right) { --range[root]; int mid = (left + right) >> 1; if (k <= range[LEFT(root)]) { root = LEFT(root); right = mid; } else { k -= range[LEFT(root)]; root = RIGHT(root); left = mid + 1; } } --range[root]; return left; } /** * @brief 查找小于等于n的最大的反质数 * @param n * @return */ int find_rprime(int n) { int left = 0; int right = sizeof(rprime) / sizeof(rprime[0]) - 1; while (left < right) { int mid = (left + right) >> 1; if (n > rprime[mid]) { left = mid + 1; } else if (n < rprime[mid]) { right = mid - 1; } else { return mid; } } while (left >= 0 && rprime[left] > n) --left; return left; } int main(int argc, char *argv[]) { int n, k; while (scanf("%d%d", &n, &k) == 2) { for (int i = 1; i <= n; ++i) { scanf("%s%d", child[i].name, &child[i].num); } build(0, 1, n); int index = 0; int order_index = find_rprime(n); int order = rprime[order_index]; for (int i = 1; i <= order; ++i) { k = k % (n - i + 1); if (k <= 0) { k += n - i + 1; } index = find(0, 1, n, k); int num = child[index].num; if (num > 0) { k = k + num - 1; } else { k = k + num; } } printf("%s %d\n", child[index].name, fact[order_index]); } return 0; }
相关文章推荐
- 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?(反素数求最大因子数+线段树)
- 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 Who Gets the Most Candies? 2886(线段树)
- 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? 线段树