poj 2886 (线段树+反素数打表) Who Gets the Most Candies?

http://poj.org/problem?id=2886

一群孩子从编号1到n按顺时针的方向围成一个圆,每个孩子手中卡片上有一个数字,首先是编号为k的孩子出去,如果他手上的数字m是正数,那么从他左边(顺时针)开始第m个孩子出去,如果是负的

那么从他的右边(也就是逆时针)开始第m个孩子出去~~~一直到所有的孩子出去,另外,第p个出去的孩子可以得到的糖果数量是p的约数个数,问能得到最多糖果的孩子的名字和得到的糖果数目

关于公约数最多的问题,可以利用到反素数,可以首先先打表反素数和对应的约数个数,找出约数最多的次数p,p肯定是不大于n的,然后就是模拟孩子出去的情况,只要模拟p次就行

然后用线段树模拟,与上一题插队差不多,记录下每个区间的人数,每次的顺序k表示第k个有人的区间更新为空

code

 1 #include<cstdio>
 2 using namespace std;
 3 struct point {
 4     int l,r;
 5     int mark;//记录每个区间人数
 6 };
 7 point tree[500001*4];
 8 char jjc[500001][10];
 9 int a[500001],pos;
10 int prime[]={ //反素数
11     1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,
12     20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,
13     554400
14 };
15 int numb[]={ //对应的约数个数
16     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,
17     144,160,168,180,192,200,216
18 };
19 void build (int i,int left,int right)
20 {
21     tree[i].l=left,tree[i].r=right;
22     tree[i].mark=tree[i].r-tree[i].l+1;
23     if (left==right) { return ;}
24     int mid=(left+right)/2;
25     build(i*2,left,mid);
26     build(i*2+1,mid+1,right);
27 }
28 void  update(int i,int ans)
29 {
30     if (tree[i].l==tree[i].r)
31     {
32         pos=tree[i].l;
33         tree[i].mark--;
34         return ;
35     }
36     if (ans<=tree[i*2].mark)
37        update(i*2,ans);
38     else
39        update(i*2+1,ans-tree[i*2].mark);
40     tree[i].mark=tree[i*2].mark+tree[i*2+1].mark;
41 }
42 int main()
43 {
44     int n,k,i,w,m;
45     while (scanf("%d %d",&n,&k)==2)
46     {
47         for (i=1;i<=n;i++)
48             scanf("%s %d",&jjc[i],&a[i]);
49         build(1,1,n);
50         w=0;
51         for(i=0;prime[i]<=n;i++)w=i;
52         pos=0;m=prime[w];
53         a[0]=0;
54         while (m--)
55         {
56             int num=tree[1].mark;
57             if (a[pos]>0)
58                k=((k+a[pos]-2)%num+num)%num+1;
59             else
60                k=((k+a[pos]-1)%num+num)%num+1;
61             update(1,k);
62         }
63         printf("%s %d
",jjc[pos],numb[w]);
64     }
65     return 0;
66 }
原文地址:https://www.cnblogs.com/JJCHEHEDA/p/4761089.html