CF1523H Hopping Around the Array
CF1523H Hopping Around the Array
这就是tourist等一众大佬没做出来的题吗??
Lemma
个人感觉的题眼所在
由于蚱蜢的弹跳始终向右,一个被删掉的点只会被越过一次
所以可以将删点操作转化为一次跳跃可以多跳一个
Solve
对于没有删点操作,显然可以用倍增实现快速跳跃
考虑到数据范围极小,可以直接将操作次数k直接作为一个维度存入倍增数组
每次跳跃时对前后两个k进行合并
复杂度\(O(qk^2log_2n+nk^2log_2n)\)
代码环节
写法有点恶臭,有些小细节见代码注释
#include<bits/stdc++.h>
using namespace std;
#define Mod(x) (x>=P)&&(x-=P)
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
#define erep(i,a) for(int i=hd[a];i;i=nxt[i])
typedef long long ll;
void Max(int &x,int y){(x<y)&&(x=y);}
void Min(int &x,int y){(x>y)&&(x=y);}
bool vio;
char IO;
int rd(int res=0){
bool f=0;
while(IO=getchar(),IO<48||IO>57)
f=IO=='-';
do res=(res<<1)+(res<<3)+(IO^48);
while(IO=getchar(),isdigit(IO));
return f?-res:res;
}
const int M=20005;
int fa[M][21][31],n,q,A[M],p[33];
int Mx(int &x,int y){return x+A[x]>y+A[y]?x:y;}
struct ST{
int f[22][M],lg[M];
void build(){
rep(i,2,n)lg[i]=lg[i>>1]+1;
rep(i,1,n)f[0][i]=i;
rep(j,1,20)rep(i,1,n)
f[j][i]=Mx(f[j-1][i],f[j-1][i+(1<<(j-1))]);
}
int qry(int l,int r){
int t=lg[r-l+1];
return Mx(f[t][l],f[t][r-(1<<t)+1]);
}
}T;
bool let;
int main(){
cerr<<(&vio-&let)/1024.0/1024<<endl;
n=rd(),q=rd();
rep(i,1,n)A[i]=min(n-i,rd());
T.build();
rep(i,1,n){
fa[i][0][0]=T.qry(i,i+A[i]);
rep(j,1,30)fa[i][0][j]=min(i+j+A[i],n);
//使用加长跳跃操作时必然是为了恰好跳到一个更优的位置
//否则可以节省操作
}
rep(j,1,20)rep(k,0,30)rep(i,1,n)rep(t,0,k)
fa[i][j][k]=Mx(fa[i][j][k],fa[fa[i][j-1][t]][j-1][k-t]);
while(q--){
int l=rd(),r=rd(),t=rd();
if(l==r){puts("0");continue;}
if(l+t+A[l]>=r){puts("1");continue;}
//能直接跳至终点时就直接终点,无需贪心控制范围最远
//以下同理
int ans=2;
rep(i,0,30)p[i]=l;
drep(i,20,0){
bool fl=1;
rep(j,0,30)rep(k,0,t-j)
if(fa[p[k]][i][j]+A[fa[p[k]][i][j]]+t-j-k>=r){fl=0;break;}
if(!fl)continue;
ans+=1<<i;
drep(j,30,0)drep(k,t-j,0)
p[k+j]=Mx(p[k+j],fa[p[j]][i][k]);
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号