codevs1282约瑟夫问题
Posted GXZlegend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs1282约瑟夫问题相关的知识,希望对你有一定的参考价值。
题目描述
有编号从1到N的N个小朋友在玩一种出圈的游戏。开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边。编号为1的小朋友站在编号为N的小朋友左边。首先编号为1的小朋友开始报数,接着站在左边的小朋友顺序报数,直到数到某个数字M时就出圈。直到只剩下1个小朋友,则游戏完毕。
现在给定N,M,求N个小朋友的出圈顺序。
输入
唯一的一行包含两个整数N,M。(1<=N,M<=30000)
输出
唯一的一行包含N个整数,每两个整数中间用空格隔开,第I个整数表示第I个出圈的小朋友的编号。
样例输入
5 3
样例输出
3 1 5 2 4
很好想的一道题,就是求出每次需要出圈的人的排名,然后输出并删除。
然而N为30000怎么办?
网上的题解是线段树,然而线段树不能删除,过于麻烦。
于是想到treap。
代码有点长,但很好理解。
需要注意rn虽是上次的排名,这次第一个人的排名却应该与rn相同,因为已经减少一个。
因此rn初始值为1。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 using namespace std; 5 int l[30001] , r[30001] , num[30001] , si[30001] , rnd[30001] , tot , root; 6 void pushup(int k) 7 { 8 si[k] = si[l[k]] + si[r[k]] + 1; 9 } 10 void zig(int &k) 11 { 12 int t = l[k]; 13 l[k] = r[t]; 14 r[t] = k; 15 si[t] = si[k]; 16 pushup(k); 17 k = t; 18 } 19 void zag(int &k) 20 { 21 int t = r[k]; 22 r[k] = l[t]; 23 l[t] = k; 24 si[t] = si[k]; 25 pushup(k); 26 k = t; 27 } 28 void ins(int &k , int x) 29 { 30 if(!k) 31 { 32 k = ++tot; 33 num[k] = x; 34 si[k] = 1; 35 rnd[k] = rand(); 36 return; 37 } 38 si[k] ++ ; 39 if(x < num[k]) 40 { 41 ins(l[k] , x); 42 if(rnd[l[k]] < rnd[k]) 43 zig(k); 44 } 45 else 46 { 47 ins(r[k] , x); 48 if(rnd[r[k]] < rnd[k]) 49 zag(k); 50 } 51 } 52 void del(int &k , int x) 53 { 54 if(!k) return; 55 if(x == num[k]) 56 { 57 if(l[k] * r[k] == 0) 58 k = l[k] + r[k]; 59 else if(rnd[l[k]] < rnd[r[k]]) 60 zig(k) , del(k , x); 61 else 62 zag(k) , del(k , x); 63 } 64 else if(x < num[k]) 65 si[k] -- , del(l[k] , x); 66 else 67 si[k] -- , del(r[k] , x); 68 } 69 int getrank(int k , int x) 70 { 71 if(x == num[k]) return si[l[x]] + 1; 72 else if(x < num[k]) return getrank(l[k] , x); 73 else return getrank(r[k] , x) + si[l[x]] + 1; 74 } 75 int find(int k , int x) 76 { 77 if(x <= si[l[k]]) return find(l[k] , x); 78 else if(x > si[l[k]] + 1) return find(r[k] , x - si[l[k]] - 1); 79 else return num[k]; 80 } 81 int main() 82 { 83 int n , m , i , rn = 1 , c; 84 scanf("%d%d" , &n , &m); 85 for(i = 1 ; i <= n ; i ++ ) 86 ins(root , i); 87 for(i = 1 ; i <= n ; i ++ ) 88 { 89 rn = (rn + m - 2 + si[root]) % si[root] + 1; 90 c = find(root , rn); 91 printf("%d " , c); 92 del(root , c); 93 } 94 printf("\n"); 95 return 0; 96 }
以上是关于codevs1282约瑟夫问题的主要内容,如果未能解决你的问题,请参考以下文章