线段树 + 反素数 poj2886
2011-12-17 19:45
218 查看
关于反素数:摘自此博客:http://magicode.blog.sohu.com/120450550.html
这个题主要用到线段树的思想,每次推算出要出去的人在当前剩下的人中的排位,再用线段树求出其原来的编号,即可算出每次应该出去的人,该人得到的糖果数为f(p)(p为出去的顺序,f(p)为p约数的个数
其实当总人数n确定时,p的值和f(p)的值就确定了,p为小于等于n的最大反素数
新学一个反素数的概念
反素数n,1<=i<n,则f(i)<f(n),即在1-n中,n的约数最多
由于反素数个数不多,这个题可以打表,把1-500000之间的反素数先算出来
反素数有以下两个性质
性质一:一个反素数的质因子必然是从2开始连续的质数.
性质二:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....
这两个性质都比较好证明
所以可以用递归的方法把反素数求出来
代码:
题意:输出第p个退出环的人的编号,使得p的约数最多。
解题:p的值为小于n的最大的反素数,因为此时p的约数最多。
这个题主要用到线段树的思想,每次推算出要出去的人在当前剩下的人中的排位,再用线段树求出其原来的编号,即可算出每次应该出去的人,该人得到的糖果数为f(p)(p为出去的顺序,f(p)为p约数的个数
其实当总人数n确定时,p的值和f(p)的值就确定了,p为小于等于n的最大反素数
新学一个反素数的概念
反素数n,1<=i<n,则f(i)<f(n),即在1-n中,n的约数最多
由于反素数个数不多,这个题可以打表,把1-500000之间的反素数先算出来
反素数有以下两个性质
性质一:一个反素数的质因子必然是从2开始连续的质数.
性质二:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....
这两个性质都比较好证明
所以可以用递归的方法把反素数求出来
代码:
//反素数 #include <iostream> #include <cmath> using namespace std; //32位整数的反素数只能由这几个素数构成 int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 }; int bestNum; //反素数 __int64 bestSum;//反素数的约数个数 //当数为num时,其约数个数为sum,本次对第k个素数的幂进行选取, //幂最高只能选limit, 求比n小的最大的反素数 void search(int num, __int64 sum, int k, int limit, int n) { if (k >= 9) return; if (sum > bestSum) { //更新 bestSum = sum; bestNum = num; } else if (bestSum == sum && bestNum > num) //约数个数相同时,选取较小的数 bestNum = num; int i, newNum = num; for (i = 1; i <= limit; i++) //第k个素数取i次方 { newNum *= prime[k]; if (newNum > n) break; search(newNum, sum * (i + 1), k + 1, i, n); //第k+1个素数最多取i次,根据上面的第二条性质 } } int main() { int n = 500000; cout << (int)log2(n * 1.0) << endl; int i = 0; while (n > 0) { i++; bestNum = 1; bestSum = 1; search(1, 1, 0, (int)log2(n * 1.0), n); cout << "{" << bestNum << ", " << bestSum << "}, "; n = bestNum - 1; } cout << i << endl; return 0; }
题意:输出第p个退出环的人的编号,使得p的约数最多。
解题:p的值为小于n的最大的反素数,因为此时p的约数最多。
#include <iostream> #include <cstdio> using namespace std; #define N 500005 //反素数表 int antiprime[35][2] = { {498960, 200}, {332640, 192}, {277200, 180}, {221760, 168}, {166320, 160}, {110880, 144}, {83160, 128}, {55440, 120}, {50400, 108}, {45360, 100}, {27720, 96}, {25200, 90}, {20160, 84}, {15120, 80}, {10080, 72}, {7560, 64}, {5040, 60}, {2520, 48}, {1680, 40}, {1260, 36}, {840, 32}, {720, 30}, {360, 24}, {240, 20}, {180, 18}, {120, 16}, {60, 12}, {48, 10}, {36, 9}, {24, 8}, {12, 6}, {6, 4}, {4, 3}, {2, 2}, {1, 1} }; int sum[N << 2], num ; //sum数组存储区间内的人数 char name [12]; 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 (l, m, rt << 1); build (m + 1, r, rt << 1 | 1); pushUp(rt); } void update(int p, int l, int r, int rt) { if (l == r) { sum[rt] = 0; return; } int m = (l + r) >> 1; if (m >= p) update(p, l, m, rt << 1); else update(p, m + 1, r, rt << 1 | 1); pushUp(rt); } int query(int k, int l, int r, int rt) { if (l == r) return l; int m = (l + r) >> 1; if (sum[rt << 1] >= k) return query(k, l, m, rt << 1); else return query(k - sum[rt << 1], m + 1, r, rt << 1 | 1); } int main() { int i, n, k, pos, p, candy; while (scanf ("%d %d", &n, &k) != EOF) { i = 0; while (n < antiprime[i][0]) i++; p = antiprime[i][0]; candy = antiprime[i][1]; for (i = 1; i <= n; i++) scanf ("\n%s %d", name[i], &num[i]); build (1, n, 1); i = 1; pos = k; //k为人在约瑟夫环中的相对位置,pos为该人在最初的环中的绝对位置 while (i < p) { update (pos, 1, n, 1); //删除当前这个人 //求出下一个人的在约瑟夫环中的相对位置 k += num[pos]; if (num[pos] > 0) k--; //注意:当num[pos] > 0时,pos后面的人的相对位置都要减1 k = (k % sum[1] + sum[1]) % sum[1]; //sum[1]为剩余人的人数 if (k == 0) k = sum[1]; //由相对位置求出绝对位置 pos = query(k, 1, n, 1); i++; } printf ("%s %d\n", name[pos], candy); } return 0; }
相关文章推荐
- poj 2886 Who Gets the Most Candies?(线段树单点更新+反素数)真难。。。
- poj 2886 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 线段树 (用反素数)
- ACM练级日志:POJ 2886 约瑟夫环,线段树和反素数
- poj 2886 Who Gets the Most Candies?(线段树、反素数)
- POJ 2828 && 2886 线段树?二分?
- poj 2886 线段树+反素数
- poj2886线段树(单点修改,区间查询)
- POJ 2886 线段树 反素数
- POJ 2886 线段树对约瑟夫问题的模拟
- poj 2886 Who Gets the Most Candies?(线段树单点更新)
- 线段树:POJ2886 Who Gets the Most Candies?
- POJ 2886 线段树单点更新
- POJ 2886 Who Gets the Most Candies? (线段树 约瑟夫环问题变种)
- poj 2886 Who Gets the Most Candies? (树状数组+二分+反素数)
- 线段树单点更新+反素数 poj-2886-Who Gets the Most Candies