Who Gets the Most Candies? POJ - 2886 (线段树)
按顺时针给出n个小孩,n个小孩每个人都有一个纸,然后每个人都有一个val,这个val等于自己的因子数,如果这个val是正的,那就顺时针的第val个孩子出去,如果是负的话,就逆时针的第val个孩子出去,所以可以用线段树维护一个区间内的孩子数,然后找到下一个孩子是这些人里的第k个人,用线段树找到剩下的第k个人的位置,然后把这个地方更新成0,这样模拟过程.
反素数:反素数就是从区间1 - i 内的数的因子数都比 i 的因子数少的数,这题中因为同样的val值时选择出队早的人,其实就是1-n内的最大反素数m,就说明是第m个人的因子数是最大的,然后我只需要模拟前m次就可以了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<map> #include<set> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define first fi #define second se #define lowbit(x) (x & (-x)) typedef unsigned long long int ull; typedef long long int ll; const double pi = 4.0*atan(1.0); const int inf = 0x3f3f3f3f; const int maxn = 500005; const int maxm = 305; using namespace std; int n, m, tol, T; struct Node { char name[15]; int k; }; Node node[maxn]; int sum[maxn << 2]; int RPrime[]= { 0,1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120, 20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960, 554400 }; int fact[]= { 0,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,100,108,120,128, 144,160,168,180,192,200,216 }; void pushup(int root) { sum[root] = sum[root << 1] + sum[root << 1 | 1]; } void build(int left, int right, int root) { if(left == right) { sum[root] = 1; return ; } int mid = (left +right) >> 1; build(left, mid, root << 1); build(mid+1, right, root << 1 | 1); pushup(root); } int update(int left, int right, int k, int root) { if(left == right) { sum[root]--; return left; } int mid = (left + right) >> 1; int ans; if(sum[root << 1] >= k) ans = update(left, mid, k, root << 1); else ans = update(mid+1, right, k-sum[root << 1], root << 1 | 1); pushup(root); return ans; } int main() { int k; while(~scanf("%d%d", &n, &k)) { for(int i=1; i<=n; i++) scanf("%s%d", node[i].name, &node[i].k); build(1, n, 1); int ansnum; for(int i=1; RPrime[i]<=n; i++) { m = RPrime[i]; ansnum = fact[i]; } tol = n; int pos; for(int i=1; i<=m; i++) { tol--; pos = update(1, n, k, 1); if(tol == 0) break; if(node[pos].k > 0) k = ((k + node[pos].k - 2) % tol + tol) %tol + 1; else k = ((k + node[pos].k - 1) % tol + tol) % tol + 1; } printf("%s %d\n", node[pos].name, ansnum); } return 0; } /* 7 3 a 3 b 2 c -5 d 4 e 8 f 2 g -6 */