HDU 3089 (快速约瑟夫环)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3089

题目大意:一共n人。从1号开始,每k个人T掉。问最后的人。n超大。

解题思路

除去超大的n之外。就是个约瑟夫环的裸题。

约瑟夫环递推公式,n为人数,k为步长。

f(1)=0

f(n)=[f(n-1)+k]%i  i∈[2,n]

f(n)还要经过起始位置修正,设起始位置为s,即ans=[f(n)+s]%n。

基本约瑟夫环优化就是当k=1的时候,每次递推就是在+1,可以直接算出来快速跳过,f(n)=f(1)+n-1

 

当n超大的时候,可以照着这种思路快速简化递推过程。在递推后期,f(x)+k在很长的周期内<i,假设有m个周期,

那么这些周期合并后的结果相当于f(x)+m*k。可以快速跳过。条件限制是: f(x)+m*k<i+(m-1)

可以推出来:

当m=1时,条件限制: f(x)+k<i

当m=2是,条件限制: f(x+1)+k<i+1=f(x)+2*k<i+1

当m=m时,条件限制:f(x)+m*k<i+(m-1)

化简有m<(i-f(x)-1)/(k-1),若能整除,就是(i-f(x)-1)/(k-1)-1,否则就是(i-f(x)-1)/(k-1)直接取整。

这样,i+=m,f(x)+=m*k,快速跳过了中间过程。

若i+m>n,说明快速跳越界了,这时候可以直接算出f(n)=f(x)+(n-i-1)*m。

 

#include "cstdio"
#define LL long long
LL solve(LL n,LL k,LL s=1)
{
    if(k==1) return (n-1+s)%n;
    LL ans=0;
    //ans=(ans+k)%i
    for(LL i=2;i<=n;)
    {
        if(ans+k<i) //快速跳跃
        {
            LL leap;
            if((i-ans-1)%(k-1)==0) leap=(i-ans-1)/(k-1)-1;
            else leap=(i-ans-1)/(k-1);
            if(i+leap>n) return ((ans+(n+1-i)*k)+s)%n;
            i+=leap;
            ans+=leap*k;
        }
        else
        {
            ans=(ans+k)%i;
            i++;
        }
    }
    return (ans+s)%n;
}
int main()
{
    //freopen("in.txt","r",stdin);
    LL n,k;
    while(scanf("%I64d%I64d",&n,&k)!=EOF)
    {
        LL ans=solve(n,k);
        if(ans==0) printf("%I64d\n",n);
        else printf("%I64d\n",ans);
    }
}

 

### HDU 443 约瑟夫问题解析 #### 解题思路 约瑟夫环问题是经典的算法挑战之一,在处理此类问题时,通常采用递推的方法来寻找规律。对于HDU 443而言,核心在于理解当人数减少一位后剩下的序列如何映射回原有序列中的位置[^1]。 每当移除一名参与者时,剩余成员会形成一个新的更短的循环结构。假设当前总共有`n`名玩家参与游戏,并按照某种规则决定谁会被淘汰出局(比如每数到特定数字就被排除),那么最终存活者的索引可以通过构建一个函数`f(n)`表示出来。这个函数描述了在规模为`n`的情况下最后一个幸存者的位置与较小规模子问题解决方案间的关系。 具体来说,设`f(n)`代表初始状态下有`n`个人时最后剩下那个人原本所在的位置,则可以建立如下递推公式: \[ f(n)=(f(n−1)+k)\% n \] 这里`k`指的是报数周期长度,即每隔多少位就有人被淘汰。而求解过程就是不断地缩小圈子大小直至只剩一人为止[^2]。 #### 代码实现 下面给出Python版本的具体编码方式用于计算给定条件下谁能成为最后一人站立的人: ```python def josephus_problem(n, k): pos = 0 # 初始化第一个仅有的元素下标为0 for i in range(2, n + 1): # 循环迭代增加人数至目标数量 pos = (pos + k) % i # 更新新加入后的安全位置 return pos + 1 # 返回实际编号而非数组索引形式的结果 if __name__ == "__main__": N = int(input()) # 输入参加游戏的人数 K = int(input()) # 输入间隔数K result = josephus_problem(N, K) print(f"The survivor is at position {result}.") ``` 上述程序接收两个参数作为输入:一个是总的参赛人员数目`N`;另一个则是计数步长`K`。它利用简单的数学运算实现了高效的解答方案而不必逐一模拟整个流程,从而能够应对较大的数据范围需求[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值