http://poj.org/problem?id=2886
一道借助线段树找出第k个位置的题。
题意是,有n个人,他们手中拿着一张写着不为零的数的牌。开始的时候是从第k个人开始的,数到的人出列,然后从那个人的位置开始数d个人,d是他手上的牌的数字,数到的下一个出列,如此反复。第i个出列的人可以得到F(i)个糖果,F(i)是因数的个数。
这题主要问题在计算下一个人的位置时,如果next(也就是这个人手上拿的数)是负数的话,就要调整一下位置,因为这时的-1相当于是0了。然后质因数,就直接预处理一下,其他的都没什么大问题了。没调整负数的情况,wa了一次。。。
代码如下:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdlib> 5 6 #define lson l, m, rt << 1 7 #define rson m + 1, r, rt << 1 | 1 8 9 using namespace std; 10 11 const int maxn = 500005; 12 int cntFac[maxn], maxCnt[maxn]; 13 14 void pre() { 15 for (int d = 1; d < maxn; d++) { 16 for (int i = d; i < maxn; i += d) { 17 cntFac[i]++; 18 } 19 } 20 for (int i = 1; i < maxn; i++) { 21 maxCnt[i] = (cntFac[maxCnt[i - 1]] >= cntFac[i]) ? maxCnt[i - 1] : i; 22 } 23 // for (int i = 0; i < 20; i++) { 24 // printf("%d : %d %d\n", i, cntFac[i], maxCnt[i]); 25 // } 26 } 27 28 int rec[maxn], cnt[maxn << 2]; 29 char name[maxn][12]; 30 31 void up(int rt) { 32 cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1]; 33 } 34 35 void build(int l, int r, int rt) { 36 if (l == r) { 37 cnt[rt] = 1; 38 return ; 39 } 40 int m = (l + r) >> 1; 41 42 build(lson); 43 build(rson); 44 up(rt); 45 } 46 47 int locate(int _p, int l, int r, int rt) { // the k-th person, begin from 1 48 if (l == r) { 49 cnt[rt] = 0; 50 return l; 51 } 52 int m = (l + r) >> 1, ret; 53 54 if (_p <= cnt[rt << 1]) ret = locate(_p, lson); 55 else ret = locate(_p - cnt[rt << 1], rson); 56 up(rt); 57 58 return ret; 59 } 60 61 int calNext(int cur, int next, int size) { 62 if (next < 0) next++; 63 return (((cur + next - 1) % size) + size - 1) % size + 1; 64 } 65 66 int deal(int n, int k) { 67 int ret = 0, tmp = 0; 68 69 build(1, n, 1); 70 rec[0] = k + 1; 71 // printf("%d\n", maxCnt[n]); 72 for (int i = 0, endi = maxCnt[n]; i < endi; i++) { 73 ret = calNext(ret, rec[tmp], n - i); 74 tmp = locate(ret, 1, n, 1); 75 // printf("ret %d\n", ret); 76 // printf("tmp %d\n", tmp); 77 // puts("~~~"); 78 } 79 80 return tmp; 81 } 82 83 int main() { 84 int n, k; 85 86 // freopen("in", "r", stdin); 87 pre(); 88 while (~scanf("%d%d", &n, &k)) { 89 for (int i = 1; i <= n; i++) { 90 scanf("%s %d", name[i], &rec[i]); 91 } 92 printf("%s %d\n", name[deal(n, k)], cntFac[maxCnt[n]]); 93 } 94 95 return 0; 96 }
——written by Lyon