POJ 2886 Who Gets the Most Candies?(线段树)

Who Gets the Most Candies?

题目
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?
题意

N个孩子从1到N面对面顺时钟坐成一圈,从第一次是第k个孩子开始出圈,下一次就是这个孩子的第A个孩子出圈,A为正数从左数,A为负从右数,第p个出圈的的孩子可以得到F(p)个糖果,F(p)为p的约数的个数,输出得到最多糖果的人的名字和糖果数。

思路

题目要求的最大的F(p)就是小于n的约数最多的数,可以先预处理出来,剩下的就是找出第p个人。出圈第p个人可以模拟依次求出,线段树储存的是该位置是否有人,也就是未出圈的为1,出圈的位置为0。线段树用来查找1到n内的还未出圈的第k个人的编号。

在一个人出圈后要推出下一个出圈人的编号。
k表示1到n中的第k个还未出圈的人,当A>0时,下一个出圈人是从1开始第k = ((k - 1 + child[pos].val - 1) % mod + mod) % mod + 1 个未出圈的人;当A<0时,k = ((k - 1 + child[pos].val) % mod + mod) % mod + 1 。mod是还在圈内的人数,每次出圈都要减一,因为取模是从0开始,所以要先减一,取模后加一,A>0是多减一是因为当第k个人出圈时,k之后的下标都要减一,而A<0时不减。

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 5e5 + 10;

struct node
{
	int l, r, val;
}t[MAXN * 4];

struct n
{
	char s[100];
	int val;
}child[MAXN];

int y[MAXN], id;
void init(int n)
{
	for (int i = 1; i <= n; i++)
	{
		for (int j = i; j <= n; j += i)
			y[j]++;
	}
	id = 1;
	int maxx = y[1];
	for (int i = 2; i <= n; i++)
	{
		if(maxx < y[i])
		{
			maxx = y[i];//预处理出最多糖果数
			id = i;
		}
	}
}

void pushup(int n)
{
	t[n].val = t[n * 2].val + t[n * 2 + 1].val;
}

void build(int n, int l, int r)
{
	t[n].l = l;
	t[n].r = r;
	if(l == r)
	{
		t[n].val = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(n * 2, l, mid);
	build(n * 2 + 1, mid + 1, r);
	pushup(n);
}

int update(int n, int pos)//找出还在圈内的第k个人的编号
{
	int l = t[n].l, r = t[n].r;
	if(l == r)
	{
		t[n].val--;
		return l;
	}
	int mid = (l + r) / 2, res;
	if(pos <= t[n * 2].val) res = update(n * 2, pos);
	else res = update(n * 2 + 1, pos - t[n * 2].val);
	pushup(n);
	return res;
}

int main()
{
	int n, k;
	while (~scanf("%d %d", &n, &k))
	{
		init(n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%s %d", child[i].s, &child[i].val);
		}
		build(1, 1, n);
		int pos = 0, mod = t[1].val;
		child[0].val = 0;
		int ans_id = id;
		while (id--)
		{
			if(child[pos].val > 0)
				k = ((k - 1 + child[pos].val - 1) % mod + mod) % mod + 1;
			else
				k = ((k - 1 + child[pos].val) % mod + mod) % mod + 1;
			pos = update(1, k);
			mod = t[1].val;
		}
		printf("%s %d\n", child[pos].s, y[ans_id]);
	}
}
发布了26 篇原创文章 · 获赞 2 · 访问量 429

猜你喜欢

转载自blog.csdn.net/D_Bamboo_/article/details/99059841