约瑟夫环加强版用线段树解决m,,这类问题还可以拓展,只是一个思路,用线段树的思路要学习

本文探讨了约瑟夫问题及其扩展,并通过线段树数据结构实现了高效求解。介绍了如何利用线段树查找和更新人员编号,以及在类似问题中应用倒序思考的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一类题还有一个重点就是

数据结构 倒序考虑会存在某种关系的思虑 十分重要

铭记这种思路

 

题意:

  n个人每个人有一个id还有一个numI ,开始从第k个人开始,第k个被拿出去,然后下一个被拿出去的是从第k个人往下数numI个,如果numI是正数那么就顺时针数numI个,如果是负数,就逆时针数abs(numI)个。第i个被拿出的人,得的分数,为i的因子个数。问谁的分数最高.

 

 

解答:

 

首先求最大分数是求反素数问题

先看什么是反素数

对于任何正整数x,起约数的个数记做g(x).例如g(1)=1,g(6)=4.

如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数.

现在给一个N,求出不超过N的最大的反素数.

 

然后求第I个人是谁

 

如果模拟是 n^2的时间复杂度。但是用线段数做可以降低到  nlogn

已知当前轮的所有人的新编号,怎么知道下一个被拿走的人的编号呢?

看约瑟夫环问题怎么进行更新

现在n中第k个人被杀死,他逆时针的第m个人(下个被杀死的),那个人在剩余的n-1个人中是第((k-m2-1)%(n-1)+(n-1))%(n-1)+1个,他顺时针第m2个人(下一个被杀死)在那个人是剩余的n-1个人中是第((k+m2-2)%(n-1)+(n-1))%(n-1)+1
(规则人从1到n编号,被杀死后,依然是按照原来的顺序从1到n-1编号)

 

 

先看线段数结构

struct tnode
{
    int l,r,sum;
    int mid(){return (l+r)/2;}
}

sum是这一段上还剩多少人。

所以在查找的时候我们相当于是二分查找剩下的第 i 个人是原来最开始的第 几号。并且更新把这个人剔除后的sum值。

见下面

int find(int nod,int m)
{
    tree[nod].sum--;
    if(tree[nod].l==tree[nod].r)
        return tree[nod].l;
    if(tree[L(nod)].sum>=m)
        return  find( L(nod),m  );
    if(tree[L(nod)].sum<m)
        return find(R(nod),m-tree[L(nod)].sum);
}

这样就可以找到 这一轮谁被剔除。

这个方法很巧妙。

 

 

poj 2828也是这一类问题的拓展

题意

 

N 个人排队,

4 (4个人排队)

0 77  

1 51      

1 33          

2 69     表示 名字叫77那个人插到第0位,名字为51那个人插到第1位,名字为33那个人插到第1位,名字为69那个人插到第2位,最后排队序列77 33 69 51。求这个最后排队序列。

 

主要是考虑倒序关系,然后用线段树预留位置。预留位置线段树操作跟约瑟夫十分类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值