CF797E Array Queries

Solution

和弹飞绵羊有点像,所以想这题可能和分块有什么关系。于是想到按值域来分块。

\(k\) 比较大的时候,容易发现跳的次数就非常少,以至于暴力跳都能过。于是当 \(k > \sqrt{n}\) 的时候,不妨就直接暴力地跳。复杂度 \(O(n\sqrt{n})\)

\(k\) 比较小的时候,也就是 \(k\leq \sqrt{n}\),发现这样的 \(k\) 很少,所以可以直接对每个 \(k\) 预处理出来从位置 \(p\) 跳完需要的步数。容易写出方程

\[f_{p,k}=f_{p+a_p+k,k}+1 \]

那么 \(O(n\sqrt{n})\) 预处理就可以了,每次查询 \(O(1)\)

#include<stdio.h>
#include<math.h>
#define N 100007
#define M 321

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

int f[N][M],n,a[N],sz;

int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    sz=(int)(sqrt(n)+0.5);
    for(int i=n;i;i--)
        for(int j=1;j<=sz;j++)
            if(i+a[i]+j>n) f[i][j]=1;
            else f[i][j]=f[i+a[i]+j][j]+1;
    int Q=read();
    while(Q--){
        int p=read(),k=read(),ret=0;
        if(k<=sz) printf("%d\n",f[p][k]);
        else{
            while(p<=n) p+=a[p]+k,++ret;
            printf("%d\n",ret);
        }
    }
}
posted @ 2020-12-26 08:33  Kreap  阅读(61)  评论(0编辑  收藏  举报