poj2886 Who Gets the Most Candies?

poj2886 Who Gets the Most Candies?

这道题题意对于一般的ACMER应该不是什么问题吧!

首先是个约瑟夫问题的升级版

1).告诉你第一次是顺时针第k个人出队

2).某个人(编号为 i) 出队后,下个出队的是从这个开始查第num[i]个人,若num[i]<0,为逆时针数,否则顺时针数。

3).重复步骤2).,直到全部出队。

4).输出出队序号中,那个序号的约数最多的那个人名及约数个数。

这里需要知道一个知识:反素数。

详见http://www.cnblogs.com/shen1000/archive/2012/07/29/2613877.html

有了反素数,我们就知道那个序号为最终答案了。

怎么求出那个序号是谁呢?对于这个,目前我只知道用模拟来找出。

思路:每次找出第几个需要要出队的人得位置,然后根据位置,找到下个需要出队的位置。
线段树功能:update:出队一个人,以及找到出队人的下标。 query:找出出对人的左边有多少未出队的人。

详见代码:

View Code
  1 #include<iostream>

  2 #include<string>

  3 #include<queue>

  4 #include<map>

  5 #include<cmath>

  6 #include<stack>

  7 #include<algorithm>

  8 using namespace std;

  9 const int maxn = 500555;

 10 char name[maxn][12];

 11 int num[maxn];

 12 int rprim[35][2] = {

 13     498960,200,332640,192,277200,180,221760,168,166320,160,

 14     110880,144,83160,128,55440,120,50400,108,45360,100,

 15     27720,96,25200,90,20160,84,15120,80,10080,72,

 16     7560,64,5040,60,2520,48,1680,40,1260,36,

 17     840,32,720,30,360,24,240,20,180,18,

 18     120,16,60,12,48,10,36,9,24,8,

 19     12,6,6,4,4,3,2,2,1,1};

 20 

 21 //1.bulid();

 22 //2.query(a,b)

 23 //3.update(a,b)

 24 #define lson l , m , rt << 1

 25 #define rson m + 1 , r , rt << 1 | 1

 26 

 27 int sum[maxn<<2];

 28 int n,k;

 29 //根据题意做相关修改,询问时的操作 

 30 int operate(int a,int b){

 31     return a+b;

 32 }

 33 void PushUp(int rt){

 34     sum[rt]=operate(sum[rt<<1],sum[rt<<1|1]);

 35 }

 36 void bulid(int l=1,int r=n,int rt=1){

 37     if(l==r){// 据题意做相关修改

 38         sum[rt]=1;return ;

 39     }

 40     int m=(l+r)>>1;

 41     bulid(lson);

 42     bulid(rson);

 43     PushUp(rt);

 44 }

 45 void update(int p,int add=0,int l=1,int r=n,int rt=1){

 46     if(l==r){// 据题意做相关修改

 47         sum[rt]=add;k=l;

 48         //printf("k=%d\n",k);

 49         return ;

 50     }

 51     int m=(l+r)>>1;

 52     if(p<=sum[rt<<1])update(p,add,lson);

 53     else update(p-sum[rt<<1],add,rson);

 54     PushUp(rt);

 55 }

 56 

 57 int query(int L,int R,int l=1,int r=n,int rt=1){

 58     if(L<=l && r<=R){

 59         return sum[rt];

 60     }

 61     int m=(l+r)>>1;

 62     int ret=0;

 63     if(L<=m)ret=operate(ret,query(L,R,lson));

 64     if(R> m)ret=operate(ret,query(L,R,rson));

 65     return ret;

 66 }

 67 

 68 int main(){

 69     int p,x,now,leftnum,rightnum,m;

 70     while(~scanf("%d%d",&n,&k)){

 71         p=0;

 72         while(n<rprim[p][0])p++;

 73         x=rprim[p][0];

 74         bulid();

 75         //printf("sum[1]=%d\n",sum[1]);

 76         for(int i=1;i<=n;i++){

 77             scanf("%s%d",name[i],&num[i]);

 78         }

 79         m=n;

 80         now=k;

 81         //printf("x=%d\n",x);

 82         for(int i=1;i<x;i++){

 83             update(now);//now出队 

 84             m--;

 85             //printf("m=%d\n",m);

 86             //转化为向左查多少人 

 87             if(num[k]%m==0){

 88                 if(num[k]>0)num[k]=m;

 89                 else num[k]=1;

 90             }else{

 91                 num[k]%=m;

 92                 if(num[k]<0)num[k]+=m+1;

 93             }

 94             leftnum=query(1,k);//找出now左边有多少个人 

 95             rightnum=m-leftnum;

 96             //printf("num[%d]=%d left=%d  right=%d\n",k,num[k],leftnum,rightnum);

 97             if(num[k]<=rightnum){

 98                 now=leftnum+num[k];

 99             }else{

100                 now=num[k]-rightnum;

101             }

102         }

103         update(now);

104         printf("%s %d\n",name[k],rprim[p][1]);

105         

106     }

107     

108     return 0;

109 }

110 /*

111 4 1

112 Tom 2

113 Jack 4

114 Mary -1

115 Sam 1

116 */

你可能感兴趣的:(get)