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

时间:2023-03-08 18:52:12
POJ 2886 Who Gets the Most Candies?(反素数+线段树)

点我看题目

题意 :n个小盆友从1到n编号按顺时针编号,然后从第k个开始出圈,他出去之后如果他手里的牌是x,如果x是正数,那下一个出圈的左手第x个,如果x是负数,那出圈的是右手第-x个,游戏中第p个离开的孩子得到的糖果是f(p)个,f(p)是p的约数的个数。

思路 : 因为f(p)是p的约数的个数,所以,要用到反素数,反素数的定义及求法。反素数s的约数个数比小于它的数的约数个数都多,最大反素数就是要找到的那个得到糖果最多的人。线段树记录的是还剩多少 人未出列。

#include <iostream>
#include <stdio.h>
#include <string.h> using namespace std; const int maxn = ;
char ch[maxn][] ;
int data[maxn] ; struct mode
{
int l,r ;
int value,sum ;
}tree[maxn * ] ;
//反素数表
int rev[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
//反素数对应的约数个数
int revs[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}; void build(int v,int l,int r)
{
tree[v].l = l ;
tree[v].r = r ;
tree[v].value = r-l+ ;
if(l == r) return ;
int mid = (l + r) >> ;
build(v*,l,mid) ;
build(v*+,mid+,r) ;
} int query(int v,int x)
{
tree[v].value-- ;
if(tree[v].l == tree[v].r) return tree[v].l ;
if(x <= tree[v*].value)
return query(v*,x) ;
else return query(v*+,x-tree[v << ].value) ;
}
int main()
{
int n, k;
while(scanf("%d %d",&n,&k) != EOF)
{
int i = ,maxx = ,p = ;
while(rev[i] <= n)
i++ ;
p = rev[i-] ;
maxx = revs[i-] ;
build(,,n ) ;
for(int j = ; j <= n ; j++)
scanf("%s %d",ch[j],&data[j]) ;
int yy ;
for(int i = ; i < p ; i++)
{
n -- ;
yy = query(,k) ;
if(n == ) break ;
if(data[yy] > )
k = (k-+data[yy]-) % n + ;
else k =( (k-+data[yy])%n+n) % n+ ;
}
printf("%s %d\n",ch[yy],maxx) ;
}
return ;
}