POJ 2886 Who Gets the Most Candies?

时间:2023-03-08 23:06:43
POJ 2886 Who Gets the Most Candies?

思路:

对于 k 位置的 孩子,他的 数字是 +num 那么因为他自己本身是要被踢走的,所以相对位置 为k= k+num-1

如果数字是 -num,那么按正着数就没影响,k=k-num。线段树存储当前区间共有多少个人,每一次找到第k (前面有k-1个)个孩子,经过的区间都要 -1,然后记录被踢走的孩子编号

对于第几个出去是最优可以预处理,网上看到了反素数,反素数 是  如果一个数  x  所有   y<x的   y的因子都小于x则称x为反素数,很明显就是小于n的最大的反素数就是我们要的答案。反素数可以预处理打表。

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include <iostream>
#define N 500050
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define debug(x) printf(#x"= %d\n",x);
using namespace std;
struct node
{
char s[];
int va;
}s[N];
int cprim[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
int fac[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
int sum[N*];
void build(int l,int r,int i)
{
sum[i]=r-l+;
if(l!=r)
{
int mid=(l+r)>>;
build(l,mid,L(i));
build(mid+,r,R(i));
}
}
int update(int l,int r,int p,int i)
{
sum[i]--;
if(l==r)
return l;
int mid=(l+r)>>;
if(p<=sum[L(i)])
return update(l,mid,p,L(i));
else return update(mid+,r,p-sum[L(i)],R(i));
}
int main() {
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=;i<=n;++i)
scanf(" %s %d",s[i].s,&s[i].va);
build(,n,);
s[].va=;
int now=;
while(cprim[now]<=n)now++;
now--;
int pre=;
for(int i=;i<=cprim[now];++i)
{
if(s[pre].va>)
{
k=(k+s[pre].va-)%sum[];
if(k<=)k+=sum[];
}else
{
k=(k+s[pre].va)%sum[];
if(k<=)k+=sum[];
}
// debug(k);
pre=update(,n,k,);
}
printf("%s %d\n",s[pre].s,fac[now]);
}
return ;
}