慈善约瑟夫

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

猜你喜欢

转载自www.cnblogs.com/qswx/p/9492568.html