Jzoj5421 嘟嘟噜

由于众所周知的原因, 冈部一直欠真由理一串香蕉.
为了封上真由理的嘴, 冈部承诺只要真由理回答出这个问题, 就给她买一车的香蕉:
一开始有n 个人围成一个圈, 从1 开始顺时针报数, 报出m 的人被机关处决. 然后下一个人再从1 开始报数, 直到只剩下一个人.
红莉栖: “这不就是约瑟夫问题吗...”
伦太郎: “助手你给我闭嘴!”
真由理虽然已经晕头转向了, 但听到有一车的香蕉, 两眼便放出了光芒.

约瑟夫问题:10^9版,m<=10^5

我们知道有一个O(n)的算法:s=(s+m)%i {i=1~n}

然而这样只能70分,我们需要改进算法

我们发现当i大于m的时候,其实有些步骤是可以合并为一步的,这个和反演里面用的那个除法很像

那我们根据当前i-s%i可以得出,接下来(i-s%i)/m步是可以合为一步走的,在接下来这些过程中,取模不会改变s+m的值

让后就可以乱搞,复杂度O(玄学)≈O(√n)

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,s=0,T;
int main(){
	freopen("mayuri.in","r",stdin);
	freopen("mayuri.out","w",stdout);
	for(scanf("%d",&T);T--;){
		s=0;
		scanf("%d%d",&n,&m);
//		for(int i=2;i<=n;++i) s=(s+m)%i;
		for(int i=2,p;i<=n;){
			p=(i-s-1)/m+1;
			if(i+p>n) p=n-i+1;
			s=(s+m*p)%(i+p-1);
			i=i+p;
		}
		printf("%d\n",++s);
	}
}

posted @ 2017-11-07 16:37  扩展的灰(Extended_Ash)  阅读(161)  评论(0编辑  收藏  举报