poj 2886

来源:互联网 发布:mac os yosemite 下载 编辑:程序博客网 时间:2024/05/16 04:57
Who Gets the Most Candies?
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 11729 Accepted: 3669Case 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 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 Adenote 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 ≤ K ≤ N) on the first line. The next Nlines 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 2Tom 2Jack 4Mary -1Sam 1

Sample Output

Sam 3

题目大意:N个孩子顺时针坐成一个圆圈且从1到N编号,每个孩子手中有一张标有非零整数的卡片。
        第K个孩子先出圈,如果他手中卡片上的数字A大于零,下一个出圈的是他左手边第A个孩子。
        否则,下一个出圈的是他右手边第(-A)个孩子。第p个出圈的孩子会得到F(p)个糖果,F(p)为
        p的因子数 求得到糖果数最多的是哪个孩子及得到多少糖果。

思       路:有了前面的总结还是没有办法顺利的做出来,思路还是不行,一直卡在怎么往左和往右找 ,
                  纠结怎么写query函数,看了别人的方法,发现,线段树只是在规定的区间内查找某个值或者
                   某个区间的情况,至于要在线段树里面写出循环暂时还是有难度的,以后遇到再修改。
                   遇到这种情况,其实还是需要数学推理公式的。

                 这道题遇到了反素数,也就是统计出所有合数的因子数目,便于查找,在n之前最大的合数p就是
                  要找的第p个人
                  需要推理的地方就在于,根据前一个跳出的人的位置求出下一个人跳出的位置
                 这里需要两个公式   假设前一人的位置是k (根据当前存在的人数)   初始位置是idx 
                  那么下一个人则是他的第data[idx]个人
                 1:data[idx]>0  说明是往序号增大的方向找到之后的第data[idx]个人  并且当前这个人已经出列
                                    下一个人的序号则是  k=(  k - 1  + data[idx]  - 1 )  % n +1;
                 2:  data[idx]<=0 说明是往序号减小的方向找到之前的第data[idx]个人  并且当前这个人已经出列
                                  下一个人的序号则是   k= ( ( k - 1 +data[idx] ) %n + n) % n  + 1;   
代码如下:
/*踏实!!努力!!*/#include<iostream>#include<stdio.h>#include<cmath>#include<cstring>#include<map>#include<queue>#include<stack>using namespace std;#define N  500005int a[37]={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,500001};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,           100,108,120,128,144,160,168,180,192,200,1314521};int sum[N<<2];int n,k,data[N];char name[N][10];void build(int l,int r,int cur){    if(l==r){        sum[cur]=1;        return ;    }    int mid=(l+r)>>1;    build(l,mid,cur<<1);    build(mid+1,r,cur<<1|1);    sum[cur]=sum[cur<<1]+sum[cur<<1|1];    return ;}int query(int k,int l,int r,int cur){    if(l==r){        sum[cur]=0;        return l;    }    int ans;    int mid=(l+r)>>1;    if(k<=sum[cur<<1])        ans=query(k,l,mid,cur<<1);    else        ans=query(k-sum[cur<<1],mid+1,r,cur<<1|1);    sum[cur]=sum[cur<<1]+sum[cur<<1|1];    return ans;}int main(){    while(scanf("%d%d",&n,&k)!=EOF){        build(1,n,1);        int Max,i=0,p;        while(a[i]<=n)            i++;        p=a[i-1];        Max=b[i-1];        for(i=1;i<=n;i++)            scanf("%s%d",name[i],&data[i]);        int idx;        int m=n;        for(i=0;i<p;i++){            n--;            idx=query(k,1,m,1);            if(n==0)                break;            if(data[idx]>0)                k=(k-1+data[idx]-1)%n+1;            else                k=((k-1+data[idx])%n+n)%n+1;        }        printf("%s %d\n",name[idx],Max);    }    return 0;}


0 0
原创粉丝点击