约瑟夫问题O(n)/O(mlogn)

题面

题解

约瑟夫问题。编号00~n1n-1,每次拿第mm个。

O(n)O(n)f[n]f[n]表示幸存的人的编号,f[n]=(f[n1]+m)%nf[n]=(f[n-1]+m)\%n

O(mlogn)O(mlogn):优化:把若干连续的mm一起计算,直到加起来的值达到第一个模数nn,然后进行下一次。每次的时间与O(n/m)O(n/m)有关,所以总时间复杂度大概可能是O(mlogn)O(mlog n)的。

假设当前答案是ansans,位置是ii,一起求的个数为kk,则:
ans+kmi+k1ans+kmgeq i+k-1移项就是ki1ansm1kgeq lceil{frac{i-1-ans}{m-1} ceil}

CODE

#include <bits/stdc++.h>
using namespace std;
int T, n, m;
int main () {
	scanf("%d", &T); while(T--) {
		scanf("%d%d", &n, &m);
		if(m == 1) { printf("%d
", n); continue; }
		int ans = 0;
		for(int i = 1; i <= n && i <= m; ++i)
			ans = (ans + m) % i;
		for(int i = m+1, j; i <= n; i = j+1) {
			j = min(i + (i-1-ans+m-2)/(m-1) - 1, n);
			ans = (ans + 1ll*m*(j-i+1)) % j;
		}
		printf("%d
", ans+1); //题目中要求的编号是1~n,所以+1
	}
}
原文地址:https://www.cnblogs.com/Orz-IE/p/12039192.html