前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >poj 2886 Who Gets the Most Candies?

poj 2886 Who Gets the Most Candies?

作者头像
用户1624346
发布2018-04-17 16:15:06
6720
发布2018-04-17 16:15:06
举报
文章被收录于专栏:calmoundcalmound

题意:n个人围城一圈,每个人决定下一个出局的人在他的第几个位置,首先出局的人是第k个人 分析:反素数+约瑟夫 这道题最主要需要理解的就是线段树是如何模拟的反素数,sum数组记录的是队列中还剩余多少个人 k表示的是在剩余里的人,其排在第几个,通过对线段树的询问找到该第k个人在初始队列中排第几个 若k<=sum[rt<<1]则进入到其左子节点,否则的话,k-sum[rt<<1|1]进入到右子节点 还有一个难点就是,剩余中k位置的更新,当next[id]>0的时候,在k-1位置的人已经被删除了,所以应该 在加上next[id]后还应该减去1,同时每次取余的时候t都已经减1了,k在加上1表示的第几个人 next[id]<0                k = ((k-1+next[id])%t+t)%t+1; next[id]>=0                k = (k-1+next[id]-1)%t+1;

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int MN= 500100;
int sum[MN<<2];
int next[MN];
char nam[MN][20];

int a[37]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,
           55440,83160,110880,166320,221760,277200,332640,498960,500001};
int b[37]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,1314521};

void PushUP(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=1;
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUP(rt);
}

int query(int k,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]--;
        return l;
    }
    int m=(l+r)>>1;
    int ret;
    if(k<=sum[rt<<1]) ret=query(k,lson);
    else
    {
        k-=sum[rt<<1];
        ret=query(k,rson);
    }
    PushUP(rt);
    return ret;
}

int main()
{
    int i,n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(i=0;i<n;i++)
          scanf("%s%d",nam[i],&next[i]);
        build(0,n-1,1);
        i=0;
        while(a[i]<=n) i++;
        int p=a[i-1];
        int MAX=b[i-1];
        int id;
        int t=n;
        for(i=0;i<p;i++)
        {
            t--;
            id=query(k,0,n-1,1);
            //id表示的是初始的位置在哪
            if(t==0) break;
            if(next[id]<0)//向前
            {
               k = ((k-1+next[id])%t+t)%t+1;
            }
            else//向后
            {//k表示的剩余人中的第几个
               k = (k-1+next[id]-1)%t+1;
            }
        }
        printf("%s %d\n",nam[id],MAX);
    }
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013-06-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档