POJ-2886 Who Gets the Most Candies?(线段树+模拟)

题目大意:n个小孩按顺时针站成一圈,每次会有一个小孩出队(第一个出队的小孩已知),在他出队时会指定下一个出队的小孩,直到所有的小孩全部出队游戏结束。第p个出队的小孩会得到f(p)个糖果,f(p)为p的正约数个数。问获得最多糖果的小孩是谁?并求出他获得的糖果数。如果有多解,只输出最先出队的那个小孩。

题目分析:先将1~n之内的具有最多约数个数并且最小的那个数打出来,然后模拟相应的次数操作即可。模拟时利用到线段树,用线段树维护区间中有多少个小孩还没有出队,每次出队一个小孩就将他在树中删除,最后利用线段树查询下一个应该出队的小孩。

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long

const int N=500000;

int f[N+5];
int tab[N+5];
int tr[N*4+5];
char p[N+5][12];
int next[N+5];

void init()
{
	memset(tab,0,sizeof(tab));
	for(LL i=1;i<=N;++i){
		if(i*i<=N) ++tab[i*i];
		for(LL j=i+1;i*j<=(LL)N;++j)
			tab[i*j]+=2;
	}
	f[1]=1;
	for(int i=2;i<=N;++i){
		if(tab[i]>tab[f[i-1]])
			f[i]=i;
		else
			f[i]=f[i-1];
	}
}

void makeTree(int rt,int l,int r)
{
	if(l==r)
		tr[rt]=1;
	else{
		int mid=l+(r-l)/2;
		makeTree(rt<<1,l,mid);
		makeTree(rt<<1|1,mid+1,r);
		tr[rt]=tr[rt<<1]+tr[rt<<1|1];
	}
}

void update(int rt,int l,int r,int x)
{
	if(l==r)
		--tr[rt];
	else{
		int mid=l+(r-l)/2;
		if(x<=mid) update(rt<<1,l,mid,x);
		else update(rt<<1|1,mid+1,r,x);
		tr[rt]=tr[rt<<1]+tr[rt<<1|1];
	}
}

int query1(int rt,int l,int r,int L,int R)
{
	if(L>R) return 0;
	if(L<=l&&r<=R)
		return tr[rt];
	else{
		int res=0;
		int mid=l+(r-l)/2;
		if(L<=mid) res+=query1(rt<<1,l,mid,L,R);
		if(R>mid) res+=query1(rt<<1|1,mid+1,r,L,R);
		return res;
	}
}

int query2(int rt,int l,int r,int cnt)
{
	if(l==r) return l;
	int mid=l+(r-l)/2;
	if(tr[rt<<1]>=cnt)
		return query2(rt<<1,l,mid,cnt);
	else
		return query2(rt<<1|1,mid+1,r,cnt-tr[rt<<1]);
}

int main()
{
	init();
	int n,k;
	while(~scanf("%d%d",&n,&k))
	{
		for(int i=0;i<n;++i)
			scanf("%s%d",p[i],&next[i]);
		memset(tr,0,sizeof(tr));
		makeTree(1,0,n-1);
		int now=k-1;
		for(int i=1;i<f[n];++i){
			int l=query1(1,0,n-1,0,now-1);
			int r=query1(1,0,n-1,now+1,n-1);
			int nn;
			if(next[now]>0)
				nn=(l-1+next[now]+l+r)%(l+r);
			else{
				next[now]=-next[now];
				next[now]%=(l+r);
				nn=(l-next[now]+l+r)%(l+r);
			}
			update(1,0,n-1,now);
			now=query2(1,0,n-1,nn+1);
		}
		printf("%s %d\n",p[now],tab[f[n]]);
	}
	return 0;
}

  

时间: 2024-12-08 20:40:27

POJ-2886 Who Gets the Most Candies?(线段树+模拟)的相关文章

poj 2886 Who Gets the Most Candies?(线段树+约瑟夫环+反素数)

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9934   Accepted: 3050 Case 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 o

poj 2886 Who Gets the Most Candies? 线段树动态求第k大的数

题意: n个小孩站一圈,每个小孩拿一个数字,从第k个孩子开始出局,然后下一个出局的孩子是刚刚出局的孩子之前或之后第v个(刚刚出局的孩子的数字是+v则之后v个,-v则之前v个),这样所有孩子终将出局,第p个出局的孩子得f(p)分,f(p)定义为p的因子个数.求分数最高的孩子. 分析: 设顺时针为正方向,关键是模拟出每次出局的孩子是剩下的孩子中的正方向的第几个,设当前要出局的是第k个,然后要求出第k个小孩的下标(pos)以便下一次计算下一个出局的孩子是第几个,这些步骤可用线段树维护. 代码: //p

POJ 2886 Who Gets the Most Candies?(线段树&#183;约瑟夫环)

题意  n个人顺时针围成一圈玩约瑟夫游戏  每个人手上有一个数val[i]   开始第k个人出队  若val[k] < 0 下一个出队的为在剩余的人中向右数 -val[k]个人   val[k] > 0 时向左数val[k]个  第m出队的人可以得到m的约数个数个糖果  问得到最多糖果的人是谁 约瑟夫环问题  n比较大 直接模拟会超时   通过线段树可以让每次出队在O(logN)时间内完成  类似上一道插队的题  线段树维护对应区间还有多少个人没出队  那么当我们知道出队的人在剩余人中排第几个

[poj 2886] 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 oth

poj 2886 Who Gets the Most Candies? (树状数组+二分+反素数)

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 11597   Accepted: 3616 Case 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

POJ 2886 Who Gets the Most Candies? 反素数+线段树

题意:变形的约瑟夫环模型,每个人有一个数字a,从第K个人开始出列,如果数字是正的,就往后数a个人出列,如果书负数,就往反方向数. 然后用最基本的线段树处理约瑟夫环的方法即可 但是题目要求的是第x个出列的人的名字,x为1-N中约数最多的数中的最小的那个.这里需要求反素数,即不大于N约数最多的. 写起来比较多,容易写错,一开始连素数打表都写作了QAQ #include <cstdio> #include <iostream> #include <cstring> #incl

POJ 2886 Who Gets the Most Candies(线段树+约瑟夫环)

题目链接:POJ 2886 Who Gets the Most Candies [题目]N个孩子顺时针坐成一个圆圈,从1~N编号,每个孩子手中有一张标有非零整数的卡片.第K个孩子先出圈,如果他手中卡片上的数字A>0,下一个出圈的是他左手边第A个孩子.A<0,下一个出圈的是他右手边第(-A)个孩子.第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数.输出得到糖果数最多的孩子的名字及糖果数目. [思路]孩子数目很大(1~500000),于是想到要用线段树来优化,然后就是模拟出圈过程.并更新

POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数)

POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数) ACM 题目地址:POJ 2886 Who Gets the Most Candies? 题意: N 个小孩围成一圈,他们被顺时针编号为 1 到 N.每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第 A 个,如果是小于 0 的, 则是

POJ - 2886 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 oth

poj 2886 Who Gets the Most Candies? (线段树单点更新应用)

poj 2886 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 t