【POJ2886】【线段树】Who Gets the Most Candies?

Description

N children are sitting in a circle to play a game.

The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the integer on his card and jumps out of the circle. The integer on his card tells the next child to jump out. Let A denote the integer. If A is positive, the next child will be the A-th child to the left. If A is negative, the next child will be the (−A)-th child to the right.

The game lasts until all children have jumped out of the circle. During the game, the p-th child jumping out will get F(p) candies where F(p) is the number of positive integers that perfectly divide p. Who gets the most candies?

Input

There are several test cases in the input. Each test case starts with two integers N (0 < N ≤ 500,000) and K (1 ≤ KN) on the first line. The next N lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 108) on their cards in increasing order of the children’s numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.

Output

Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.

Sample Input

4 2
Tom 2
Jack 4
Mary -1
Sam 1

Sample Output

Sam 3

Source

【分析】

第二题.没什么好说的。

求素数用欧拉筛,dp求一下反素数。

然后注意一下细节,线段树直接上..其实树状数组也可以。

上一次使用树状数组做的,为什么我现在每个代码都有这么长?

  1 /*
  2 唐代杜甫
  3 《月夜忆舍弟》
  4 戍鼓断人行,边秋一雁声。(边秋 一作:秋边)
  5 露从今夜白,月是故乡明。
  6 有弟皆分散,无家问死生。
  7 寄书长不达,况乃未休兵。
  8 */
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <algorithm>
 12 #include <cstring>
 13 #include <vector>
 14 #include <utility>
 15 #include <iomanip>
 16 #include <string>
 17 #include <cmath>
 18 #include <queue>
 19 #include <assert.h>
 20 #include <map>
 21 #include <ctime>
 22 #include <cstdlib>
 23 #include <stack>
 24 #define LOCAL
 25 const int MAXN = 500000 + 10;
 26 const int MAXM = 1000000 + 10;
 27 const int INF = 100000000;
 28 const int SIZE = 450;
 29 const int maxnode =  10000000 + 10;
 30 using namespace std;
 31 int n, k, people;//people为真实人数
 32 bool have[MAXN];
 33 char str[MAXN][15];
 34 struct SEGTREE{
 35        struct Node{
 36               int sum, l, r;
 37               int val;//代表权值
 38               Node *ch[2];
 39
 40               void update(){
 41                    if (l == r) return;
 42                    sum = ch[0]->sum + ch[1]->sum;
 43                    return;
 44               }
 45        }*root, mem[maxnode];
 46        int tot;//静态数组
 47
 48        Node *NEW(int val){
 49             Node *p = &mem[tot++];
 50             p->val = val;
 51             p->sum = 1;
 52             p->ch[0] = p->ch[1] = NULL;
 53             return p;
 54        }
 55        void init(){
 56             root = NULL;
 57             tot = 1;
 58             build(root, 1, n);
 59             /*change(root, 1);
 60             change(root, 2);
 61             printf("%d\n", find(root, 2));*/
 62        }
 63        void build(Node *&t, int l, int r){
 64             if (t == NULL){
 65                t = NEW(-1);
 66                t->l = l;
 67                t->r = r;
 68             }
 69             if (l == r){scanf("%s", str[l]);scanf("%d", &t->val); return;}
 70             int mid = (l + r)>>1;
 71             build(t->ch[0], l, mid);
 72             build(t->ch[1], mid + 1, r);
 73             t->update();
 74        }
 75        //将x位置的sum变为0
 76        int change(Node *&t, int l){
 77             if (t->l == l && t->r == l){
 78                t->sum = 0;
 79                have[l] = 1;//出圈
 80                return t->val;
 81             }
 82             int mid = (t->l + t->r)>>1;
 83             int tmp;
 84             if (l <= mid) tmp = change(t->ch[0], l);
 85             if (l > mid) tmp = change(t->ch[1], l);
 86             t->update();
 87             return tmp;
 88        }
 89        //返回
 90        int find(Node *&t, int l){//找到第l个人,pos记录他的位置
 91             if (t->l == t->r) return t->l;
 92             int c = t->ch[0]->sum;
 93             //if (l == (c + (have[t->ch[0]->r + 1] ^ 1))) return t->ch[0]->r + 1;
 94             if (l <= c) return find(t->ch[0], l);//左边,右边
 95             else return find(t->ch[1], l - c);
 96        }
 97 }A;
 98 int prime[MAXN];
 99 int Max[MAXN], num[MAXN];//num记录i的约束个数
100
101 void prepare(){
102      memset(prime, 0, sizeof(prime));//欧拉线性筛
103      prime[0] = 1;
104      for (int i = 2; i <= 500000; i++){
105          if (!prime[i]) prime[prime[0]++] = i;
106          for (int j = 1; j < prime[0]; j++){
107              if (prime[j] * i > 500000) break;
108              prime[i * prime[j]] = 1;
109              if (i % prime[j] == 0) break;
110          }
111      }
112      //DP+打表
113      num[0] = 0;
114      num[1] = Max[1] = 1;
115      num[498960] = 200;num[166320] = 160;
116      num[332640] = 192;num[110880] = 144;
117      num[277200] = 180;
118      num[221760] = 168;
119      int Ans = 1;
120      for (int i = 2; i <= 500000; i++){
121          //printf("%d\n", num[Max[i - 1]]);
122          if (i >= 498960) {Max[i] = 498960;continue;}
123          if (i >= 332640) {Max[i] = 332640;continue;}
124          if (i >= 277200) {Max[i] = 277200;continue;}
125          if (i >= 221760) {Max[i] = 221760;continue;}
126          if (i >= 166320) {Max[i] = 166320;continue;}
127          if (i >= 110880) {Max[i] = 110880;continue;}
128          int cnt = 0, x = -1, tmp = i;
129          for (int j = 2; j <= (int)sqrt(1.0 * i); j++) if (i % j == 0) {x = j;break;}
130          if (x == -1) num[i] = 2;//质数
131          else{
132               while (tmp % x == 0) {tmp /= x; cnt++;}
133               cnt = (cnt + 1) * num[tmp];
134               num[i] = cnt;
135          }
136          if (num[i] > num[Ans]) Ans = i;
137          Max[i] = Ans;
138      }
139 }
140 void init(){
141      memset(have, 0 ,sizeof(have));//表示第i个人是否出圈
142      people = n;
143      A.init();
144      n = Max[n];//小于等于n的最大反素数
145      //找n个人出圈就行了
146 }
147 int MOD(int x, int t) {return x%t == 0? t: x % t;}
148 void work(){
149      //if ( == 1)
150      int last = k;//表示上一个出圈人的名次
151      int t = A.change(A.root, k);//t为人手上的位置
152      //printf("%d", t);
153      for (int i = 2; i <= n; i++){//i为现在正在要出圈的人是第i个
154          //计算现在出圈人的名次
155          int now;
156          if (t < 0) now = MOD(MOD(last + t, people - (i - 1)) + (people - (i - 1)), (people - (i - 1)));
157          else now = MOD(MOD(last - 1 + t, people - (i - 1)) + (people - (i - 1)), (people - (i - 1)));
158          int tmp = A.find(A.root, now);
159          if (i == n) {printf("%s %d\n", str[A.find(A.root, now)], num[n]);return;}
160          t = A.change(A.root, tmp);
161          last = now;
162      }
163      /*A.change(A.root, 1);
164      A.change(A.root, 2);
165      printf("%d", A.find(A.root, 1));*/
166 }
167
168 int main(){
169
170     prepare();
171     while (scanf("%d%d", &n, &k) != EOF){
172           init();
173           work();
174     }
175     return 0;
176 }

时间: 2024-10-13 15:55:48

【POJ2886】【线段树】Who Gets the Most Candies?的相关文章

POJ (线段树) Who Gets the Most Candies?

这道题综合性挺强的,又牵扯到数论,又有线段树. 线段树维护的信息就是区间中有多少个人没跳出去,然后计算出下一个人是剩下的人中第几个. 我在这调程序调了好久,就是那个模来模去的弄得我头晕. 不过题确实是好题,给赞. 1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #include <string> 5 #include <algorithm> 6 #include <

POJ2886 Who Gets the Most Candies? 【线段树】+【单点更新】+【模拟】+【反素数】

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9416   Accepted: 2868 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

POJ-2886 Who Gets the Most Candies?(线段树+模拟)

题目大意:n个小孩按顺时针站成一圈,每次会有一个小孩出队(第一个出队的小孩已知),在他出队时会指定下一个出队的小孩,直到所有的小孩全部出队游戏结束.第p个出队的小孩会得到f(p)个糖果,f(p)为p的正约数个数.问获得最多糖果的小孩是谁?并求出他获得的糖果数.如果有多解,只输出最先出队的那个小孩. 题目分析:先将1~n之内的具有最多约数个数并且最小的那个数打出来,然后模拟相应的次数操作即可.模拟时利用到线段树,用线段树维护区间中有多少个小孩还没有出队,每次出队一个小孩就将他在树中删除,最后利用线

poj 2886 Who Gets the Most Candies?(线段树+约瑟夫环+反素数)

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9934   Accepted: 3050 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

POJ 2886 Who Gets the Most Candies?(线段树&#183;约瑟夫环)

题意  n个人顺时针围成一圈玩约瑟夫游戏  每个人手上有一个数val[i]   开始第k个人出队  若val[k] < 0 下一个出队的为在剩余的人中向右数 -val[k]个人   val[k] > 0 时向左数val[k]个  第m出队的人可以得到m的约数个数个糖果  问得到最多糖果的人是谁 约瑟夫环问题  n比较大 直接模拟会超时   通过线段树可以让每次出队在O(logN)时间内完成  类似上一道插队的题  线段树维护对应区间还有多少个人没出队  那么当我们知道出队的人在剩余人中排第几个

Poj2886Who Gets the Most Candies?线段树

约瑟夫环用线段数搞,一脸搞不出来的样子.反素数,太神了,先打表,然后就可以 O(1)找到因子数最多的.ps:哎.这题也是看着题解撸的. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cs

POJ 2886 Who Gets the Most Candies? 反素数+线段树

题意:变形的约瑟夫环模型,每个人有一个数字a,从第K个人开始出列,如果数字是正的,就往后数a个人出列,如果书负数,就往反方向数. 然后用最基本的线段树处理约瑟夫环的方法即可 但是题目要求的是第x个出列的人的名字,x为1-N中约数最多的数中的最小的那个.这里需要求反素数,即不大于N约数最多的. 写起来比较多,容易写错,一开始连素数打表都写作了QAQ #include <cstdio> #include <iostream> #include <cstring> #incl

[poj 2886] Who Gets the Most Candies? 线段树

Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the oth

(线段树,反素数)poj2886-Who Gets the Most Candies?

N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the inte