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;
}