[Hnoi2010]Bounce 弹飞绵羊 分块暴力

本文介绍了一个游戏算法优化案例,通过将游戏区域划分为多个区块并预处理每个区块间的跳跃路径,实现了快速查找弹射路径的功能。这种方法能够显著降低计算复杂度,适用于需要频繁更新的游戏场景。

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

41 2 1 1 31 12 1 11 1

Sample Output

23

HINT

Source

直接跳的话复杂度是O(nm),显然是无法接受的。显然我们无法优化询问这个m,那么如何从n入手优化呢?
如果跳的次数能有效减少,那么对于时间的优化是巨大的,所以我们考虑预处理一下从某个点跳到某个点需要几步
最直接的思考,倒着递推O(n),预处理每个点跳到终点要几步?对于修改较少的输入时可以接受的,可是一旦修改的次数增多,复杂度还是O(nm),
那么取折衷的方案是,我们考虑把n个数字分成若干段,每一段的大小是sqrt(n),然后预处理每一个点跳到另外的位置(该位置属于另一个区块,也有可能是不相邻的区块,因为一步可能跳很远,比一块的大小还远),以及从这个点到另一个块的那个位置需要的步数。这要查询的时候最多只要sqrt(n)的跳跃就能出结果。对于修改,我们只需要修改要修改的那个点属于的块中每个点跳到另外块的位置以及需要的步数即可,因为每个块只有sqrt(n)个点,所以总体复杂度为O(m*sqrt(n))。
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cassert>
using namespace std;

const int maxn = 222222;
//const int maxn = 22;

//to[i]:从i跳到另外的块的位置 group[i]:i点是在哪一块 step[i]:从i跳到另外的块需要的步数
int to[maxn], group[maxn], step[maxn], k[maxn], n, size;

void solve(int l, int r) {
    for (int i = r; i >= l; i --) {
        if (i + k[i] >= n) {
            to[i] = -1;
            step[i] = 1;
        } else {
            if (group[i] == group[i+k[i]]) {
                to[i] = to[i+k[i]];
                step[i] = step[i+k[i]] + 1;
            } else {
                to[i] = i + k[i];
                step[i] = 1;
            }
        }
    }
}

int work(int u) {
    int ret = 0;
    while (u != -1) {
        ret += step[u];
        u = to[u];
    }
    return ret;
}

int main() {
    scanf("%d",&n); size = (int)sqrt(n);
    for (int i = 0; i < n; i ++) scanf("%d",&k[i]);
    for (int i = 0; i < n; i ++) {
        group[i] = i / size;
    }
    solve(0, n-1);
    int m; scanf("%d",&m);
    while (m--) {
        int op, pos; scanf("%d%d",&op,&pos);
        if (op == 1) {
            printf("%d\n",work(pos));
        } else {
            int x; scanf("%d",&x);
            k[pos] = x;
            int l = pos / size * size, r = l + size - 1;
            solve(l, r);
        }
    }
    return 0;
}





【事件触发一致性】研究多智能体网络如何通过分布式事件驱动控制实现有限时间内的共识(Matlab代码实现)内容概要:本文围绕多智能体网络中的事件触发一致性问题,研究如何通过分布式事件驱动控制实现有限时间内的共识,并提供了相应的Matlab代码实现方案。文中探讨了事件触发机制在降低通信负担、提升系统效率方面的优势,重点分析了多智能体系统在有限时间收敛的一致性控制策略,涉及系统模型构建、触发条件设计、稳定性与收敛性分析等核心技术环节。此外,文档还展示了该技术在航空航天、电力系统、机器人协同、无人机编队等多个前沿领域的潜在应用,体现了其跨学科的研究价值和工程实用性。; 适合人群:具备一定控制理论基础和Matlab编程能力的研究生、科研人员及从事自动化、智能系统、多智能体协同控制等相关领域的工程技术人员。; 使用场景及目标:①用于理解和实现多智能体系统在有限时间内达成一致的分布式控制方法;②为事件触发控制、分布式优化、协同控制等课题提供算法设计与仿真验证的技术参考;③支撑科研项目开发、学术论文复现及工程原型系统搭建; 阅读建议:建议结合文中提供的Matlab代码进行实践操作,重点关注事件触发条件的设计逻辑与系统收敛性证明之间的关系,同时可延伸至其他应用场景进行二次开发与性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值