zoukankan      html  css  js  c++  java
  • [Codevs] 1282 约瑟夫问题

    1282 约瑟夫问题

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
     
    题目描述 Description

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

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

     
    输入描述 Input Description

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

     
    输出描述 Output Description

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

     
    样例输入 Sample Input

    5 3

     
    样例输出 Sample Output

    3 1 5 2 4

    分析 Analysis

    现在有一个标准的1-n的递增排列

    击鼓传花,每次数到 m 时就要去掉当前这个元素,然后继续从 0 计数

    那么定义 sum( i ) 为元素 i 之前的当前实际存在的元素数,在计算过程中,sum( i ) 才是真正的位置

    那么给每一个元素一个初始权值 1 ,维护每个元素以自己为端点的前缀和,就能愉快的计算 sum( i ) 啦

    那么设 pos 为当前要操作的元素位置,根据 AET(Apparently Easy Theory) 原理,我们知道下一步的 pos = (pos-1)%len

    但是我们计算的时候要把pos+1

    那么线段树的内容就是维护前缀和且单点置零啦

    注意查找

    这次的线段树被阉割的非常阉割

    代码 Code

     1 #include<cstdio>
     2 #include<iostream>
     3 #define mid (L+R)/2
     4 #define lc (rt<<1)
     5 #define rc (rt<<1|1)
     6 #define maxn 1000000
     7 using namespace std;
     8 
     9 int Tree[maxn],n,m;
    10 void maintain(int rt){Tree[rt] = Tree[lc]+Tree[rc];}
    11 void build(int rt,int L,int R){
    12     if(L == R) Tree[rt] = 1;
    13     else{
    14         build(lc,L,mid);
    15         build(rc,mid+1,R);
    16         maintain(rt);
    17     }
    18 }
    19 void modify(int rt,int L,int R,int pos){
    20     if(L == R) Tree[rt] = 0;
    21     else{
    22         if(pos <= mid) modify(lc,L,mid,pos);
    23         else modify(rc,mid+1,R,pos);
    24         maintain(rt);
    25     }
    26 }
    27 int query(int rt,int L,int R,int val,int remain){
    28     if(L == R) return L;
    29     else{
    30         if(val <= Tree[lc]+remain) return query(lc,L,mid,val,remain);
    31         else return query(rc,mid+1,R,val,remain+Tree[lc]);
    32     }
    33 }
    34 
    35 int main(){
    36     scanf("%d%d",&n,&m);
    37     
    38     build(1,1,n);
    39     
    40     int pos = m,ans;
    41     for(int i = n;i >= 1;i--){
    42         pos = (pos-1)%(Tree[1]);
    43 //        printf("###$$%d ",pos+1);
    44         ans = query(1,1,n,pos+1,0);
    45         printf("%d ",ans);
    46         modify(1,1,n,ans);
    47         pos += m;
    48 //        getchar();
    49     }
    50     
    51     return 0;
    52 }
    阉割的非常严重的线段树
    转载请注明出处 -- 如有意见欢迎评论
  • 相关阅读:
    js如何识别后端返回的“↵”,让其换行
    ReactNative插件
    ReactNative踩坑
    js对当前时间进行处理
    vue-awesome-swiper手动滑动后不再自动轮播的问题
    HTML5知识点汇总
    懒加载的实现原理及一些实现方法
    使用node.js实现多人聊天室(socket.io、B/S)
    [vue学习] 卡片展示分行功能简单实现
    [vue学习]快速搭建一个项目
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7491700.html
Copyright © 2011-2022 走看看