http://poj.org/problem?id=2886

这个题和插队买票那题一样 http://www.cnblogs.com/liulangye/archive/2012/06/11/2545529.html

题目大意:

一些人围成一圈第一个人跳出圈后会告诉你下一个谁跳出来

跳出了的人所得到的糖果数量和他跳出的顺序有关

线段树在这里只是一个二分搜索的作用

思路:

1.求第几个跳出者所得糖果数量

2.根据输入范围,求的第几个人是得到糖果最多的 假设是J

3.建立线段树,线段树区间表示区间内人的个数,

搜索第几个人时所经过的路径区间人数的减一

然后根据提示求的下一个跳出的人是谁  并记录第J个人是谁

代码及其注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int N=500005;
struct node
{
    int l,r;
    int sum;
}mem[N*3];
struct node1
{
    char name[12];
    int a;
}step[N];//输入名字 及其下一个跳出提示
int candysum[N];//第i个人跳出所得糖果
int ansi;//得糖果最多的人的输入序号
int I,n,c,J;//J表示第几个跳出的人得到的糖果最多
void ready()//求第i人跳出最得到的糖果数量
{
    memset(candysum,0,sizeof(candysum));
    for(int i=1;i<N;++i)
    {
        ++candysum[i];
        for(int j=i*2;j<N;j=j+i)
        {
            ++candysum[j];
        }
    }
}
void build(int x,int l,int r)//建树
{
    mem[x].l=l;
    mem[x].r=r;
    mem[x].sum=(r-l+1);
    if(mem[x].l==mem[x].r)
    return;
    int mid=(r+l)>>1;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
}
void jump(int x,int s)//s表示目前队列此区间第几个人跳出
{
    --mem[x].sum;//所到区间人数减一
    if(mem[x].l==mem[x].r)//最后结点
    {
        if(J==c)
        {
            ansi=mem[x].l;//如果是的J个人跳出 记录答案
        }
        if(n-c==0)//全跳出
        return ;
        if(step[mem[x].l].a>0)//以下是求出目前队列从线段树左起下一次第几个人跳出
        --I;
        I=((I+step[mem[x].l].a)%(n-c)+(n-c))%(n-c);
        if(I==0)
        I=n-c;
    }
    else
    {
        if(mem[x*2].sum>=s)//左边人数足够则向左搜
        {
            jump(x*2,s);
        }
        else
        {
            s-=mem[x*2].sum;//否则减去左边人数向右搜
            jump(x*2+1,s);
        }
    }
}
int main()
{
    int k;
    ready();
    while(scanf("%d %d",&n,&k)!=EOF)
    {
        J=1;
        for(int i=1;i<=n;++i)
        {
            getchar();
            scanf("%s %d",step[i].name,&step[i].a);
            if(candysum[i]>candysum[J])
            J=i;
        }
        build(1,1,n);
        I=k;
        for(c=1;c<=n;++c)
        {
            jump(1,I);
        }
        printf("%s %d\n",step[ansi].name,candysum[J]);
    }
    return 0;
}

  

 

 

 

posted on 2012-06-12 17:36  夜->  阅读(343)  评论(0编辑  收藏  举报