• luoguP3203 [HNOI2010]BOUNCE 弹飞绵羊


    P3203 [HNOI2010]BOUNCE 弹飞绵羊

    题目描述

    某天,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。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

    输出格式:

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

    输入输出样例

    输入样例#1:
    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1
    输出样例#1:
    2
    3

     思路:

      分块什么的

    坑点:

      1.注意是从0号元素开始!!!

      2.在luogu上最好不要用next数组...

    代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int M = 200000;
    const int N = 1000;
    int n,m;
    int k[M],steps[M],nxt[M];
    ///step数组存的是需要多少步跳出当前块
    ///next数组存的是跳到(下一块)的下一个点 
    int len,ks,kuai[M],l[N],r[N];///分块 
    
    void Builds()
    {
        ///块的长度
        len=sqrt(n);
        ///块的个数 
        ks=len;
        if(n%ks) ks++;
        ///分块 
        for(int i=0;i<n;i++)
            kuai[i]=(i-1)/len;
        /*
            因为块数是从0号开始计数的,
            当i==(√n)时如果不进行-1,
            会被分到第一块,
            但事实上它是第0块的,
            所以进行-1 
        */ 
        for(int i=1;i<=ks;i++)
        {
            l[i]=(i-1)*len;
            ///r[i]=i*len-1中-1的原因是:
            ///因为数组是从0号开始储存的 
            r[i]=i*len-1;
        }
        ///将最后一块的右端手动设置为n的长度 
        r[ks]=n;
        for(int i=n-1;i>=0;i--)
        {
            int now=i+k[i];
            ///如果下一步跳到的地方已经跳出最远的距离n的话 
            if(now>=n)
                ///更新步数:跳一步就跳出去 
                steps[i]=1,
                ///这里重要!需要手动将next数组设置一个不可能出现的数值 
                    nxt[i]=-1;
            else 
            ///假如在同一块中 
                if(kuai[i]==kuai[now])
                ///更新步数,i的步数由now的步数多跳一步来到当前(点)位置 
                    steps[i]=steps[now]+1,
                    ///更新接下来跳到的点是... 
                        nxt[i]=nxt[now];
            else
            ///不在一块中 
                steps[i]=1,
                ///跳到now这个点 
                    nxt[i]=now; 
        }
    }
    
    int ask(int pre)
    {
        int ans=0;
        while(pre!=-1)
        {
            ans+=steps[pre];
            pre=nxt[pre];
        }
        return ans;
     } 
    
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&k[i]);
        ///开始分块 
        Builds();
        scanf("%d",&m);
        for(int i=0,c;i<m;i++)
        {
            scanf("%d",&c);
            if(c==1)
            {
                int pre;
                scanf("%d",&pre);
                printf("%d
    ",ask(pre)); 
            }
            else 
            {
                int pre,ki;
                scanf("%d%d",&pre,&ki);
                ///更新k值 
                k[pre]=ki;
                ///因为更改k之后只会影响到当前块,并且只会影响他前面的 
                for(int j=pre;j>=l[kuai[pre]];j--)
                {
                    int now=j+k[j];
                    if(now>=n)
                        steps[j]=1,
                            nxt[j]=-1;
                    else 
                        if(kuai[j]==kuai[now])
                            steps[j]=steps[now]+1,
                                nxt[j]=nxt[now];
                    else
                        steps[j]=1, 
                            nxt[j]=now; 
                }
            }
        }
        return 0;
    }
    View Code

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    Guava Cache,Java本地内存缓存使用实践
    Guava-retry,java重试组件
    [leetcode] 31. 下一个排列
    [leetcode] 30. 与所有单词相关联的字串(cn第653位做出此题的人~)
    [leetcode] 29. 两数相除
    [leetcode] 28. 实现strStr()
    [leetcode] 27. 移除元素
    [leetcode] 26. 删除排序数组中的重复项
    [leetcode] 25. k个一组翻转链表
    [leetcode] 24. 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/7125274.html
Copyright © 2020-2023  润新知