POJ2886--Who Gets the Most Candies?

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 ≤ KN) 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 2
Tom 2
Jack 4
Mary -1
Sam 1

Sample Output

Sam 3

/*
反素数的求法。
搜百度搜了好久都找不到细讲的,最后既然搜到队长的博客O(∩_∩)O哈哈~
显然素数的因子数为2;
至于非素数,可以分解为质因子之积
i=2^b1*3^b2^5^b3------等等
所以i的因子个数=(b1+1)*(b2+1)*(b3+1)~~~*(bn+1)
反素数的求法:筛选法+DP;素数的约数个数显然是2,对于合数,先求出其
一个质因子,假设是a1,则反复试除a1,求得b1,而在DP过程中已经求得了
N/a1的约数个数,设为g(N/a1),则g(N)=g(N/a1)*(b1+1)/b1
求出反素数后,我们就可以得到n内最大的那个反素数设为k,问题转换为如何求得
谁是第k个跳出来的人。
PS:做此题一定小心别左右不分。。。。
*/
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 500108
bool isp[maxn+1000];
int num[maxn+1000];
int yinshu[maxn+1000];
int maxid[maxn+1000];//用来存最大反素数的id
char Name[maxn+1000][12];
int nextt[maxn+1000];
int winnerid;
struct ST
{
	int l,r,res;
}st[4*maxn];
void init()//筛选素数
{
	isp[1]=1;
	for(int i=2;i<720;i++)
	{
		if(!isp[i])
		{
			for(int j=i*i;j<=maxn;j+=i)
			{
				isp[j]=1;
				if(!yinshu[j])//这里少个判断,WA了若干次
				yinshu[j]=i;
			}
		}
	}
}
void get()//这一步是求出maxn内,每个数因子数的个数
{
	num[0]=0;
	num[1]=1;
	maxid[1]=1;
	for(int i=2;i<=maxn;i++)
	{
		if(!isp[i])num[i]=2;//如果是个素数,那么他的因子数就是2
		else//如果不是个素数,那么
		{
			int s,t,ant=1;
			s=t=i/yinshu[i];//接下来我们要反复除yinshu[i].求出i的质因子yinshu[i]的指数
			while(t==yinshu[i]||(isp[t]&&yinshu[i]==yinshu[t]))
			{
				t/=yinshu[i];
				ant++;
			}
			num[i]=num[s]*(ant+1)/ant;
		}
		if(num[i]>num[maxid[i-1]])
		{
			maxid[i]=i;
		}
		else maxid[i]=maxid[i-1];
	}
}
void buildtree(int id,int l,int r)
{
	st[id].l=l;st[id].r=r;
	st[id].res=r-l+1;
	if(l==r)return;
	int mid=(l+r)>>1;
	buildtree(2*id,l,mid);
	buildtree(2*id+1,mid+1,r);
}
int update(int id,int l,int r,int p)//要来T第P个人
{
	st[id].res--;
	if(st[id].l==st[id].r)
	{
		return st[id].l;
	}
	if(st[2*id].res>=p)
	{
		return update(2*id,l,st[2*id].r,p);
	}
	else return update(2*id+1,st[2*id+1].l,r,p-st[2*id].res);
}
int main()
{
	int n,star,sum,p;//sum用来存此时的真实人数
	init();get();
	while(scanf("%d%d",&n,&star)==2)
	{
		sum=n;
		buildtree(1,1,n);
		for(int i=1;i<=n;i++)
		{
			scanf("%s%d",Name[i],&nextt[i]);
		}
		p=star;
		//想想如何得到要踢的人是第几个人
		for(int i=1;i<=n;i++)
		{
			int z=update(1,1,n,p);
			if(i==maxid[n])
			{
				winnerid=z;	
			}
			sum--;
			if(nextt[z]>0)//要踢左边第几个
			{
				if(sum<=1)p=1;
				else
				{	p=p-1+(nextt[z]%sum);
					if(p>sum)p-=sum;
					if(p<=0)p+=sum;
				}
			}//这里感觉上不会出错
			else//要踢右边第几个,这里就错啦
			{
				if(sum<=1)p=1;
				else
				{
					p=p+(nextt[z]%sum);
					if(p<=0)p+=sum;
					if(p>sum)p-=sum;
				}
			}
		}
		printf("%s %d\n",Name[winnerid],num[maxid[n]]);
	}
	return 0;
}
		
				


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值