• 【CODEVS1282】约瑟夫问题


    Description

    有编号从1到N的N个小朋友在玩一种出圈的游戏。开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边。编号为1的小朋友站在编号为N的小朋友左边。首先编号为1的小朋友开始报数,接着站在左边的小朋友顺序报数,直到数到某个数字M时就出圈。直到只剩下1个小朋友,则游戏完毕。

    现在给定N,M,求N个小朋友的出圈顺序。

    Input

    唯一的一行包含两个整数N,M。(1<=N,M<=30000)

    Output

    唯一的一行包含N个整数,每两个整数中间用空格隔开,第I个整数表示第I个出圈的小朋友的编号。

    Sample Input

    5 3

    Sample Output

    3 1 5 2 4

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=100000;
    int cnt=0;
    struct treetype{
        int lptr,rptr,Fat; //左右孩子及父节点指针
        int Left,Right; 
        int sum; //[Left,Right)中的人数
    }t[2*maxn];
    void buildtree(int ll,int rr){
        int cur=++cnt;
        t[cur].Left=ll; t[cur].Right=rr;
        if (t[cur].Right!=t[cur].Left+1){
            t[cur].lptr=cnt+1; t[cnt+1].Fat=cur;
            buildtree (ll,(ll+rr)/2);
            t[cur].rptr=cnt+1; t[cnt+1].Fat=cur;
            buildtree ((ll+rr)/2,rr);
            t[cur].sum=t[t[cur].lptr].sum+t[t[cur].rptr].sum;
        }else{
            t[cur].lptr=0; t[cur].rptr=0; t[cur].sum=1;
        }
    }
    
    int calc(int x){ //找圈中的第x个人(出圈),并更新线段树 
        int k=1;
        while (t[1].sum<x) x-=t[1].sum;  //x(out)<=t[1].sum,使x在圈内 
        while (t[k].Left!=t[k].Right-1){ //非单位区间 
            if (t[t[k].lptr].sum<x){ //在右区间 
                x-=t[t[k].lptr].sum;
                k=t[k].rptr;
            }else k=t[k].lptr; //在左区间 
        }//出圈者是t[k].Left
        printf("%d ",t[k].Left);
        for (int kk=k;kk>0;kk=t[kk].Fat) t[kk].sum--; //更新线段树 
        return t[k].Left; 
    }
    
    int query(int k,int ll,int rr){ //查询区间[ll,rr)中的人数
        if (ll<=t[k].Left &&rr>=t[k].Right) return t[k].sum;
        else{
            int ans=0;
            if (ll<(t[k].Left+t[k].Right)/2) ans+=query(t[k].lptr,ll,rr);
            if (rr>(t[k].Left+t[k].Right)/2) ans+=query(t[k].rptr,ll,rr);
            return ans;
        }
    }
    
    int main(){
        int n,m,k;
        scanf("%d%d",&n,&m);//n个人 数到m报数 
        buildtree(1,n+1);
        int out=m;
        for (int i=1;i<=n;i++){
            k=calc(out); //k出圈
            k=query(1,1,k+1); //[1,k+1)中的人数 
            out=k+m; //out可能大于t[1].sum 
        }
        return 0;
    }
  • 相关阅读:
    关于ArcGis for javascrept查询ArcGis server图层信息的方式
    Elasticsearch教程之基础概念
    C# 将日期转换成中文格式
    .Net 自定义Excel模板导出数据
    JavaScript判断浏览器类型
    简单的json传送数据
    Oracle替换临时表空间
    Python多线程循环
    crontab执行不生效-【问题篇】
    Python将MySQL表数据写入excel
  • 原文地址:https://www.cnblogs.com/liumengyue/p/5119595.html
Copyright © 2020-2023  润新知