PKU 2886 反素数+线段树

来源:互联网 发布:csol三米优化刀 编辑:程序博客网 时间:2024/04/30 05:48
Who Gets the Most Candies?
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 7896 Accepted: 2352Case 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

[Submit]   [Go Back]   [Status]   [Discuss]

Home Page   Go Back  To top



题目大意:几个孩子围成一圈,从第K个孩子开始跳出,每个孩子的手里有一张牌,上面写着非零的正整数,从第K个孩子开始,他跳出后,如果手里的牌上的数字是正数,那么从他左边开始越过牌上正整数的人数来得到下一个要跳出的人。如果手上的牌是负数,那么从他的右边开始越过负数的绝对值的人数得到下一个要跳出的人,没一个人跳出之后所得到的糖果数都是 他跳出的序号的约数个数,求得到糖果最多的孩子 以及他得到的糖果数。


先说这个题目要用到的第一个知识点,线段树。先创建一个1---n的线段树,每个区间的附加信息为当前区间的人数,如果序号为p的人要跳出,那么,如果tree[rt<<1]>=p,那么证明要跳出的人的序号在左边的区间,否则,要跳出的人在右边的区间,序号为p-tree[rt<<1]。从根节点一直向下处理,直到编号为p的人跳出即可。每次Update操作的时候,对应的区间的人数都要减掉1,因为每次操作一定会跳出一个,这样在update的函数中把pushup函数的要求也就实现了。。。。


另一个 知识点就是反素数,定义是如果小于等于N的任意数的因子个数都少于N的因子个数,那么N为反素数,即1---N的区间内N的因子数最多 。所以,如果有n个人,那么我们要找的得到最多糖果数就是n以内的最大反素数的因子数。至于得到最多糖果的人是谁,我们在找最大反素数的过程中,对应的那个人便是的到糖果最多的人。


至于求最大反素数以及对应的最大因子数的算法我还在实现中,写好了立刻贴上来


题目的代码如下:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define maxn 555555#define lson l , m, rt<<1#define rson m+1, r, rt<<1|1using namespace std;int n,k;int tree[maxn<<2];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};typedef struct node{char name[15];int value;}JD;JD person[maxn];void build(int l,int r,int rt){tree[rt]=r-l+1;if(l==r)return ;int m=(l+r)>>1;build(lson);build(rson);}int update(int k,int l,int r,int rt){tree[rt]--;if(l==r){return l;}int m=(l+r)>>1;if(k<=tree[rt<<1]) return update(k,lson);else{k-=tree[rt<<1];return update(k,rson);}}int main(void){int i;int n,k,&mod=tree[1];while(scanf("%d%d",&n,&k)==2){for(i=1;i<=n;i++)scanf("%s%d",person[i].name,&person[i].value);build(1,n,1);int cnt=0;while(cnt<35 && antiprime[cnt]<=n)cnt++;cnt--;int pos=0;person[pos].value=0;for(i=0;i<antiprime[cnt];i++){if(person[pos].value>0)k=((k+person[pos].value-2)%mod+mod)%mod+1;elsek=((k+person[pos].value-1)%mod+mod)%mod+1;pos=update(k,1,n,1);}printf("%s %d\n",person[pos].name,factorNum[cnt]);}return 0;}

原创粉丝点击