转载自:http://blog.csdn.net/sdj222555/article/details/6878651

反素数拓展参照:http://blog.csdn.net/ACdreamers/article/details/25049767

题目大意就是一群熊孩子做游戏,第一个出队的人是编号为k的人。此后出队的人就是按照前一个人手里的编号。如果是正数+m就是这个人的左边的第m个人。如果是负数-m,就是 这个人的右边第m个人。由于这个人出队了。对下一个人有影响,所以+m的时候,是k+m-1。-m的时候是k+m。因为是他后边的人所以没有影响。因为可能出现负数和0的情况,所以就有下面的取模时的处理。线段树的每个节点保存的是这个区间还有多少个位置。所以每次更新时,如果左孩子节点的空位够了,搜索左孩子,否则搜索右孩子。可以建树参照对样例模拟一下。

还不懂怎么打反素数表。所以是cooy的。

附代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 #define lson l, m, rt<<1
 7 #define rson m+1, r, rt<<1|1
 8 #define N 500010
 9 
10 int tree[N<<2];
11 
12 const int antiprime[] = { // 反素数表
13     1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,
14     1260,1680,2520,5040,7560,10080,15120,20160,25200,
15     27720,45360,50400,55440,83160,110880,166320,221760,
16     277200,332640,498960,554400,665280
17 };
18 
19 const int factorNum[] = { // 对应的约数个数
20     1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,
21     64,72,80,84,90,96,100,108,120,128,144,160,168,180,
22     192,200,216,224
23 };
24 
25 struct child{  // 保存输入时的节点信息
26     char name[15];
27     int val;
28 }c[N];
29 
30 void Build(int l, int r, int rt) {  // 建树
31    tree[rt] = r-l+1;
32    if (l == r)
33    return;
34    int m = (l+r)>>1;
35    Build(lson);
36    Build(rson);
37 }
38 
39 int Update(int p, int l, int r, int rt) {  // 第p个人出去。Update函数可以理解。
40     tree[rt]--;
41     if (l == r)
42     return r;
43     int m = (l+r)>>1;
44     if (p<=tree[rt<<1])
45     return Update(p, lson);
46     else return Update(p-tree[rt<<1], rson);
47 }
48 
49 int main() {
50    int i, n, &mod = tree[1];
51    // mod 保存的就是一共有多少个人、
52    int k;
53 
54    while(~scanf("%d%d", &n, &k)) {
55      // 输入建树
56      for (i=1; i<=n; ++i) {
57         scanf("%s%d", c[i].name, &c[i].val);
58      }
59      Build(1, n, 1);
60 
61      // 小于等于n的最大的反素数。
62      int cnt = 0;
63      while(cnt < 35 && antiprime[cnt] <= n) {
64         cnt++;
65      }
66      cnt--;
67      // 先找到1-n范围内的约束个数最大的数。
68 
69      // pos是记录当前位置该出队的人的ID
70      int pos = 0;
71      c[pos].val = 0;
72 
73      // 找antiprime[cnt]出队的人的名字、
74      for (i=0; i<antiprime[cnt]; ++i) {  // 循环的次数就是直到这个人出队。
75 
76         // 这两个if是根据 这个人手里牌的编号来推算下一个出队列的人的当前位置、
77         if (c[pos].val > 0)
78         k = ((k+c[pos].val-2)%mod+mod)%mod+1;
79         else k=((k+c[pos].val-1)%mod+mod)%mod+1;
80 
81        // pos 记录的是当前循环出队的人的所在位置、
82         pos = Update(k, 1, n, 1);
83         cout << pos << "====\n";
84      }
85      printf("%s %d\n", c[pos].name, factorNum[cnt]);
86    }
87    return 0;
88 }
View Code

 

posted on 2015-10-03 18:15  小小八  阅读(211)  评论(0编辑  收藏  举报