【洛谷】P1145-约瑟夫
题目链接
解析
与最经典的约瑟夫问题略有不同,这题要求刚好使队伍后一半人全部出列。
注:队伍序号从0开始!
这里我采用的是求出出队的人在当前队伍中序号的方法
做法为用号数m对当前总人数sum取模再减一,获得本次报数起点需要向右移动的距离(dis,当距离为-1时向左移动)
dis = m%sum - 1;
上次出列序号out+需要移动的距离dis,对sum取模,可以获得下次出列的序号,只要保证该序号大于等于k即是坏人出列
out = (out + dis + sum) % sum;
//括号内再加一个sum是为了对移动距离为-1时取模
当sum削减到k时说明坏人已全部出列。
代码
#include<iostream>
using namespace std;
int k, m;
int main()
{
int ans = 0;
cin >> k;
for (m = k + 1;ans == 0;m++)
{
int out = 0, sum = 2 * k, dis;
while (sum > k)
{
dis = m % sum - 1;
out = (out + dis + sum) % sum;
if (out >= k && out < 2 * k)
sum--;
else
break;
if (sum == k)
ans = m;
}
}
cout << ans;
return 0;
}
优化
m可以不用逐级递增,而是使m满足
(2n-1)k<m<=2nk,k=1,2,3…
以省去必定不满足条件的m。