CF797E Array Queries
Link
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);
}
}
}