zoukankan      html  css  js  c++  java
  • [HNOI2010]弹飞绵羊

    洛谷题目链接:弹飞绵羊

    题目描述

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

    输入输出格式
    输入格式:

    第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。

    接下来一行有n个正整数,依次为那n个装置的初始弹力系数。

    第三行有一个正整数m,

    接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。

    输出格式:

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

    输入输出样例
    输入样例#1:
    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1
    输出样例#1:
    2
    3
    说明
    对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

    稍微解释一下题意:大概就是给出一个长度为n序列,将一只绵羊从指定位置出发,所在位置上面的数字代表它可以向后跳这么多的距离,求出从一个位置出发需要多少次才可以跳出序列。其中有修改操作。

    题解:

    首先我们想一下,可以通过模拟的方式来推出所需次数,但是这样很显然是会超时的。那么我们应该如何才能优化这个模拟的过程呢?
    我们可以用mv[]记录一个元素需要几次才能跳出它所在的块,out[]记录跳到的下一个块上的位置,l[],r[]记录一个块的左右端点,w[]记录向后跳的距离。
    那么很显然可以得出每个元素的信息的递推式:

    • 如果一个元素可以跳到下一个块上,则mv[i] = 1 , out[i] = w[i]+i;
    • 如果不能跳到下一个块上,则会跳到下一个位置,此时mv[i] = mv[i+w[i]]+1,out[i] = out[i+w[i]];

    然后注意一下要从后面往前推,每次修改一个元素时就重新统计这个元素所在的块就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200000+5;
    const int inf=2147483647;
    
    int n, m, block, num;
    int w[N], b[N];
    int l[N], r[N];
    int out[N], mv[N];
    
    int gi(){
        int ans = 0 , f = 1; char i = getchar();
        while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
        while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
        return ans * f;
    }
    
    void updata(int x,int y){
        for(int i=y;i>=x;i--)
        if(i+w[i] > r[b[i]]) mv[i] = 1 , out[i] = i+w[i];
        else mv[i] = mv[i+w[i]]+1 , out[i] = out[i+w[i]];
    }
    
    int query(int x){
        int pos = x , res = 0;
        while(pos <= n) res += mv[pos] , pos = out[pos];
        return res;
    }
    
    int main(){
        //freopen("data.in","r",stdin);
        //freopen("ans.out","w",stdout);
        int x, y, flag; n = gi(); block = sqrt(n);
        for(int i=1;i<=n;i++) w[i] = gi();
        for(int i=1;i<=n;i++) b[i] = (i-1)/block+1;
        for(int i=1;i<=block;i++)
        l[i] = (i-1)*block+1 , r[i] = i*block;
        if(n % block) num = block+1;
        else num = block;
        l[num] = (num-1)*block+1 , r[num] = n;
        m = gi(); updata(1,n);
        for(int i=1;i<=m;i++){
        flag = gi(); x = gi()+1;
        if(flag == 1) printf("%d
    ",query(x));
        else y = gi() , w[x] = y , updata(l[b[x]],r[b[x]]);
        }
        return 0;
    }
    
  • 相关阅读:
    vue项目发布到服务器之后出现空白页和图片找不到的问题
    H5中设置一个元素一直在页面的最底部
    vue项目打包出现的问题(日常记录)
    vue写H5注册页面
    vue项目中动态图片生成
    Java中boolean类型占用多少个字节
    Java将一个目录下的所有数据复制到另一个目录下
    Java使用递归找出某目录下的所有子目录以及子文件
    实现短信验证码
    C#连接Oracle数据库(直接引用dll使用)
  • 原文地址:https://www.cnblogs.com/BCOI/p/8711581.html
Copyright © 2011-2022 走看看