poj 2886 Who Gets the Most Candies?(线段树和反素数)
题目:http://poj.org/problem?id=2886
题意:N个孩子顺时针坐成一个圆圈且从1到N编号,每个孩子手中有一张标有非零整数的卡片。
第K个孩子先出圈,如果他手中卡片上的数字A大于零,下一个出圈的是他左手边第A个孩子。
否则,下一个出圈的是他右手边第(-A)个孩子。第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数。求得到糖果数最多的是哪个孩子及得到多少糖果。
跟上一个 约瑟夫环的题目很像,就是加了一个反素数。
虽然我还是不太理解,但还是无耻的从别人的结题报告上把反素数表copy了下来。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 using namespace std; 7 const int maxn = 500000 + 10; 8 int val[maxn]; 9 char name[maxn][20]; 10 11 int a[37]= {1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040, 12 7560,10080,15120,20160,25200,27720,45360,50400, 13 55440,83160,110880,166320,221760,277200,332640,498960,500001 14 }; //反素数表 15 int b[37]= {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, 16 100,108,120,128,144,160,168,180,192,200,1314521 17 }; //反素数对应的值 18 struct node 19 { 20 int l, r, sum; 21 }tr[maxn<<2]; 22 23 void build(int t, int l, int r) 24 { 25 tr[t].l = l; tr[t].r = r; 26 tr[t].sum = r - l + 1; 27 if(l == r) 28 return; 29 int mid = (l+r)>>1; 30 build(2*t, l, mid); 31 build(2*t+1, mid+1, r); 32 } 33 int query(int num, int t) 34 { 35 tr[t].sum--; 36 if(tr[t].l == tr[t].r) 37 return tr[t].l; 38 if(tr[2*t].sum >= num) 39 return query(num, 2*t); 40 else 41 return query(num-tr[2*t].sum, 2*t+1); 42 } 43 int main() 44 { 45 int n, k, i, p, Max; 46 int x; 47 while(~scanf("%d%d", &n, &k)) 48 { 49 i = 0; 50 Max = 0; p = 0; 51 while(a[i] <= n) 52 i++; 53 p = a[i-1]; Max = b[i-1]; //第几个出去的。最大值 54 build(1, 1, n); 55 for(i = 1; i <= n; i++) 56 scanf("%s%d",name[i], &val[i]); 57 58 for(i = 0; i < p; i++) 59 { 60 n--; 61 x = query(k, 1); 62 if(n == 0) break; 63 if(val[x] > 0) 64 k = (k-1+val[x]-1)%n + 1; 65 else 66 k = (k-1+val[x]%n+n)%n + 1; 67 } 68 printf("%s %d\n",name[x], Max); 69 } 70 return 0; 71 }