慈善约瑟夫

Description

你一定听说过约瑟夫问题吧?即从n个人中找出惟一的幸存者。现在老约瑟夫将组织一个皆大欢喜的新游戏,假设n个人站成一圈,从第1个人开始交替的去掉游戏者,但只是暂去掉(例如,首先去掉2),直到最后剩下惟一的幸存者为止。

幸存者选出后,所有比幸存者号码高的人每人将得到1TK(一种货币),永久性的离开。其余剩下的人将重复以上的过程,比幸存者号码高的每人将得到1Tk后离开。经过这样的过程后,一旦人数不再减少,则最后剩下的那些人将得到2TK。

请你计算一下老约瑟夫一共要付出多少钱?

Analysis

题意表述不清,没有讲清Joseph游戏的关键数字,或许例如,首先去掉2是个提示,经尝试确实如此。

很明显,这就是个多轮Joseph问题,处理每轮游戏后的奖金即可。那么,单轮Joseph怎么处理呢?对于i人的游戏来看,每次处决第2个人后,人数变为i-1,只是开始的下标改变了,所以再显然不过的状态转移:

dp[i]=2+dp[i-1]

当然,因为是个环所以要加上求余处理,为了方便将序号设为0~n-1,可以在之后处理时再加上1。得出n人游戏的幸运儿序号j后,每次将奖金加上n-j,再更新n和j,直到n=j则加上2·n。

Code

#include <bits/stdc++.h>

int n,ans,dp[32768];

int main(){
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	std::cin>>n;
	dp[1]=0;
	for(int i=2;i<=n;i++)
		dp[i]=(dp[i-1]+2)%i;
	for(int i=1;i<=n;i++)
		dp[i]++;
	int id=dp[n];
	while(n>id){
		ans+=n-id;
		id=dp[n=id];
	}
	ans+=2*n;
	std::cout<<ans<<std::endl;
	return 0;
}
posted @ 2018-08-17 11:49  Srzer  阅读(305)  评论(0编辑  收藏  举报