题目描述
约瑟夫问题(https://baike.baidu.com/item/约瑟夫问题),n个人,1 2报数 1出队( 就是体育课的时候1 2报数 1出队,2留下),q次询问,每次求第x个人是第几个出队的
输入描述:
第一行两个数n,q 接下来q行,每行一个数x,表示询问
输出描述:
一行输出一个询问的答案
示例1
输入
4 3 2 3 4
输出
3 2 4
说明
1 2 3 4围成一圈,第一轮:1 2报数,1出队,2留下,3出队,4留下,第二轮,2出队,4留下
备注:
q≤500000 n和x≤1e18
题解:
递归模拟:
递归基: n = 1 时 直接放回1
设定一个bool值d 表示该圈是选择奇数还是选择偶数,起始时选择的是奇数,所以d = 1 (1,3,5..)
当n为奇数时且d为1时,下一个环d = 0。
当n为偶数时且d为0时,下一个环d = 1。
上式读者可以画图验证。
tot表示当前环删除了多少个。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll work(ll n,ll m,bool d) { if(n == 1) return 1; if((m & 1) == d) return ((m-1) >> 1) + 1; ll tot; if(d) tot = ((n-1) >> 1)+ 1; else tot = n >> 1; m = d ? m >> 1 : (m >> 1) + 1; d = d ^ (n & 1); return work(n - tot, m ,d) + tot; } int main() { ll n,m; int q; while(~scanf("%lld%d",&n,&q)) { while(q--) { scanf("%lld",&m); printf("%lld\n",work(n,m,1)); } return 0; } }