poj 2886 Who Gets the Most Candies?(反质数+线段树模拟约瑟夫)

来源:互联网 发布:淘宝发表论文是真的吗? 编辑:程序博客网 时间:2024/05/16 08:06
Who Gets the Most Candies?
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 5528 Accepted: 1579Case 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 A denote 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 N lines 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

Source

POJ Monthly--2006.07.30, Sempr

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

题意:有n个小孩在玩约瑟夫,每个小孩手上都有一个数值,第k个小孩先出去,然后给出手上的数值v,大于0的话就是从他左边开始数的第v个小孩,否则就是从右边数的第-v个小孩接着出列,直到所有小孩出列,第p个出列的小孩,将拿到f(p)个糖果,f(p)表示p的正因子个数,现在要求最多糖果的小孩。。。

分析:首先,最多糖果其实就是小于n的最大反质数cnt,反质数满足f[x]>f[i](1<i<x),当然反质数比较少,可以直接预处理出来。。。接下去就是模拟约瑟夫直到第cnt个小孩出列为止。。。原来约瑟夫可以用线段树模拟啊= =,一直都是用各种指针。。。。


代码:

#include<cstdio>#include<iostream>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define FOR(i,l,h) for(int i=(l);i<=(h);++i)#define FDT(i,h,l) for(int i=(h);i>=(l);--i)using namespace std;const int mm=555555;const int antiprime[]={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,665280};const int factorNum[]={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,224};int sum[mm<<2];int val[mm];char name[mm][11];void build(int l,int r,int rt){    sum[rt]=r-l+1;    if(l==r)return;    int m=(l+r)>>1;    build(lson);    build(rson);}int updata(int p,int l,int r,int rt){    --sum[rt];    if(l==r)return l;    int m=(l+r)>>1;    if(sum[rt<<1]>=p)return updata(p,lson);    else return updata(p-sum[rt<<1],rson);}int main(){    int n,k,cnt,pos,&m=sum[1];    while(~scanf("%d%d",&n,&k))    {        build(1,n,1);        FOR(i,1,n)scanf("%s%d",name[i],&val[i]);        FOR(i,0,36)            if(antiprime[i]<=n)cnt=i;        pos=val[0]=0;        FOR(i,1,antiprime[cnt])        {            if(val[pos]>0)k=((k+val[pos]-2)%m+m)%m+1;            else k=((k+val[pos]-1)%m+m)%m+1;            pos=updata(k,1,n,1);        }        printf("%s %d\n",name[pos],factorNum[cnt]);    }    return 0;}